home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / os2 / pmics091.arj / PMICS.C < prev    next >
C/C++ Source or Header  |  1993-05-30  |  74KB  |  2,222 lines

  1. /*
  2.     PMICS -- PM interface for playing chess on internet chess server
  3.     Copyright (C) 1993  Kevin Nomura
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     Author can be reached at email: chow@netcom.com
  20. */
  21. /*****************************************************************************
  22.   This is version 0.91 (beta) of PMICS.
  23.     bugs:
  24.     - background fill pattern not filling whole window
  25.     - occasional transposition of data seen in terminal window during
  26.           challenge, but apparently no lost data
  27.  
  28.         version 1.0 work items:
  29.         - full modem parameters (com port, baud, num bits, parity, colours)
  30.     - check mark on menu for lock/unlock
  31.     - clock timer should be keyed to absolute time
  32.     - resizability
  33.     - make match request dialog "modeless"
  34.  
  35.     next release work items:
  36.     - gnuchess interface -- play locally or connect it to ICS
  37.     - rexx port?
  38.     - big board for 1024x768 displays
  39.     - modem redial on BUSY
  40.     - bughouse mode?  (need ICS support)
  41.  
  42.         5/7     add pattern to background fill GpiSetPattern,GpiQueryPS
  43.                 use static controls for status window texts
  44.         5/8     option for I/O through session DosDupHandle,DosCreatePipe
  45.     5/9    lock/unlock (local echo of board moves)
  46.     5/13    detect what colour I am
  47.             scrollable/refreshable text using ListBox
  48.     5/14    found lost data bug: WinPostMsg failed
  49.              incremental board update
  50.         5/18    dialog box for match requests
  51.     5/19    fix update bug; gnuchess format for moves
  52.     5/28    color options; SCORE_FILE
  53.  
  54.     icc /Sa /Ti- /Si /q /c /G4 /O- /Tdp /Fi /Gm pmics.c bitmaps.c
  55.     link386 pmics.obj+bitmaps.obj /m /noi /st:20000 /nol /pm:pm
  56. ******************************************************************************/
  57.  
  58. #define INCL_WIN
  59. #define INCL_GPI
  60. #define INCL_GPIPRIMITIVES
  61. #define INCL_DOSPROCESS
  62. #define INCL_DOSFILEMGR
  63. #define INCL_DOSDEVIOCTL
  64. #define INCL_DOSDEVICES
  65. #define INCL_DOSDATETIME
  66. #define INCL_DOSQUEUES
  67. #define INCL_DOSEXCEPTIONS
  68. #include <os2.h>
  69. #include <stdio.h>
  70. #include <string.h>
  71. #include <stdlib.h>
  72. #include <time.h>
  73. #include "pmics.h"
  74.  
  75. #define LOG_FILE        "pmics.log"   // debug log
  76. #define SCORE_FILE      "pmics.sco"   // game scores
  77.  
  78. #define LBX             1
  79. #define LBY             1
  80.  
  81. /* frame window parameters */
  82. #define APP_TITLE       "PMICS - Internet Chess Server"
  83. #define WCP_MAIN        "WCP_MAIN"
  84. int FW_X, FW_Y;
  85. int CW_X, CW_Y;
  86.  
  87. /* board window parameters */
  88. #define WCP_BOARD       "WCP_BOARD"
  89. #define BW_X            (SQUARESIZE*8)
  90. #define BW_Y            BW_X
  91. #define FW_BW_X         0
  92. #define FW_BW_Y         (CW_Y - BW_Y)   // upper left
  93.  
  94. /* message window parameters */
  95. #define WCP_MSG         "WCP_MSG"
  96. #define MW_X            CW_X
  97. #define MW_Y            (CW_Y - BW_Y)
  98. #define FW_MW_X         0               // lower left
  99. #define FW_MW_Y         0
  100. #define TERM_SAVED_LINES 200
  101.  
  102. /* stats window parameters */
  103. #define WCP_STAT        "WCP_STAT"
  104. #define SW_X            260
  105. #define SW_Y            BW_Y
  106. #define FW_SW_X (BW_X+8)
  107. #define FW_SW_Y FW_BW_Y
  108.  
  109. // session stuff
  110. PID     ChildPID = 0;
  111. #define HF_STDIN   0
  112. #define HF_STDOUT  1
  113. #define PIPESIZE   1024
  114. void (*CommSpeak)(char *s);
  115.  
  116.  
  117. class GAME
  118. {
  119. private:
  120.   char state;            // 0=invalid, 1=valid
  121.  public:
  122.   char  piece[8][8];
  123.   char  opiece[8][8];    // from previous refresh, for incremental update
  124.   int   moveNum, prevMoveNum;
  125.   int   gameNum;
  126.   char  playerW[17], playerB[17], opponent[17];
  127.   char  onMove, prevOnMove;
  128.   int   timeW, timeB, lastMoveTime;
  129.   char  atTop;   /* 'B' or 'W' */
  130.   char  oAtTop;
  131.   char  clockRun;
  132.   char  lastMove[8];    // o-o shortest, P/a2-a4 longest
  133.   GAME() {state = 0;}
  134.   char is_valid() {return (state != 0);}
  135.   void init();
  136.   void plot(HPS hps);
  137.   void update(HPS hps);
  138.   void move(HPS hps, char rankFrom, char fileFrom, char rankTo, char fileTo);
  139.   void orient(char colour);   // ' ' toggles
  140.   void plot_piece(HPS hps, char piece, char rank, char file);
  141.   void msg_style_8(char *s);
  142.   int IsInitialPosition() {return (moveNum == 1) && (onMove == 'W');}
  143. } board;
  144.  
  145. struct
  146. {
  147.   char   BoardSize;
  148.   char   CommMode;
  149.   char   ComPort;
  150.   ULONG  ComBaud;
  151.   ULONG  WinX, WinY;    // user-specified window dimensions
  152.   char   DialString[128];
  153.   char   *wsc, *bsc, *wpc, *bpc;    // colour specs for squares, pieces
  154.   char   *fcp;          // program executed in session mode
  155. } profile;
  156.  
  157. typedef struct 
  158. {
  159.   char  RatedMode[8], BlitzMode[9], OppName[17];
  160.   char  OppRating[11];
  161.   int   TimeMin, TimeSec;
  162. } MATCHPARMS;
  163.  
  164. typedef enum
  165. {
  166.   PI_EMPTY = 0,
  167.   PI_B_ROO, PI_B_KNI, PI_B_BIS, PI_B_QUE, PI_B_KIN, PI_B_PAW,
  168.   PI_W_ROO, PI_W_KNI, PI_W_BIS, PI_W_QUE, PI_W_KIN, PI_W_PAW
  169. };
  170. #define is_black(p) ((p)>=PI_B_ROO && (p)<=PI_B_PAW)
  171. #define is_white(p) ((p)>=PI_W_ROO && (p)<=PI_W_PAW)
  172. #define BITS_BYTES (SQUARESIZE*SQUARESIZE/8)
  173.  
  174. class TXQ
  175. {
  176.  private:
  177.   enum {queuel=12, queuec=255, winl=9};
  178.   char buf[queuel][queuec];
  179.   int headl, headc;
  180.   int taill, tailc;
  181.  public:
  182.   TXQ();
  183.   void CharIn(char c);
  184.   char *FinishLine();
  185.   char *CurLine();
  186.   char *WinLine(int n);
  187.   char *BufLine(int n);
  188.   void Dump();
  189. } txq;
  190.  
  191. char    *pi_bits[13];       // bitmap pointers
  192. HAB     hab;            // anchor block
  193. FILE    *logfile;            // debug log
  194. FILE    *scorefile;        // game scores
  195. HFILE   hcom;            // com port
  196. int     SQUARESIZE;
  197. DATETIME        keyDt;
  198. int     txti = 0;
  199. char    lastAction[64] = "";    // mouse button 2 action
  200.  
  201. HWND    hTerm = NULLHANDLE;
  202. HWND    hFrame = NULLHANDLE;
  203. HWND    hClient = NULLHANDLE;
  204. HWND    hBoard = NULLHANDLE;
  205. HWND    hStat = NULLHANDLE;
  206.  
  207. typedef struct _timel_parm
  208. {
  209.   HWND  hwnd;
  210.   int   ms;
  211. } timel_parm;
  212.  
  213. /*********************************/
  214. /* Internal function prototypes  */
  215. /*********************************/
  216. static VOID _System timel(timel_parm *tp);
  217. static VOID _System TxComIn(ULONG dummy);
  218.  
  219. /* message parsers */
  220. static void ProcessChallenge(HWND hwnd, char *s);
  221.  
  222. static void setup(int i);
  223. static void TermPut(HWND hwnd, HPS hps, char *s);
  224. static char ComInit();
  225. static int SessionInit();
  226.  
  227. #define IN(a,low,high) ((a)>=(low) && (a)<=(high))
  228. #define at(hwnd,a,b) {POINTL p; p.x=(a); p.y=(b); GpiMove(hwnd,&p);}
  229.  
  230. /*****************************************************************************/
  231. MRESULT EXPENTRY FrameProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  232. {
  233.   static HPS    hps;                        /* presentation space handle */
  234.   static HDC    hdc;
  235.  
  236.   switch( msg )
  237.     {
  238.     case WM_CREATE:
  239.       return (MRESULT) FALSE;
  240.  
  241.     case WM_PAINT:
  242.       {
  243.         RECTL   rect;
  244.         HRGN    hrgn;
  245.         SIZEL   sizel;
  246.  
  247.         hps = WinBeginPaint ( hwnd , 0L , &rect );
  248.  
  249.         GpiSetPattern(hps, PATSYM_DENSE6);
  250.         GpiQueryPS(hps, &sizel);
  251.         rect.xLeft = 0;
  252.         rect.yBottom = 0;
  253.         rect.xRight = sizel.cx;
  254.         rect.yTop = sizel.cy;
  255.         GpiSetColor(hps, CLR_WHITE);
  256.         GpiSetBackColor(hps, CLR_BLUE);
  257.         hrgn = GpiCreateRegion(hps, 1, &rect);
  258.         GpiPaintRegion(hps, hrgn);
  259.         GpiDestroyRegion(hps, hrgn);
  260.  
  261. /*      WinFillRect (hps, &rect, CLR_BLUE);*/
  262.         WinEndPaint (hps);
  263.         return (MRESULT) NULL;
  264.       }
  265.  
  266.     case WM_CLOSE:
  267.       WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  268.       // clean up child processes
  269.       if (ChildPID != 0)
  270.     {
  271.       RESULTCODES  res;
  272.       PID pid;
  273. /*      if (DosKillProcess (DKP_PROCESSTREE, ChildPID) == 0)
  274.         DosWaitChild(DCWA_PROCESSTREE, DCWW_WAIT, &res, &pid, ChildPID);
  275. Naturally this hung the system the first time I tried it.  sheesh */
  276.       DosKillProcess (DKP_PROCESS, ChildPID);   // just blow it away
  277.     }
  278.       return (MRESULT) NULL;
  279.  
  280.     case WM_CHAR:
  281.       {
  282.         /* pass keypress to children (Term, in particular) */
  283. /*        WinBroadcastMsg(hwnd, msg, mp1, mp2, BMSG_POST);*/
  284.         WinPostMsg(hTerm, msg, mp1, mp2);
  285.         return (MRESULT)TRUE;
  286.       }
  287.  
  288.     case WM_COMMAND:
  289.       switch (SHORT1FROMMP(mp1))
  290.         {
  291.         case IDM_DIAL:
  292.           (*CommSpeak)("ATDT2419796\015");
  293.           return (MRESULT) NULL;
  294.         case IDM_SERVER_LOGIN:
  295.           (*CommSpeak)("telnet aragorn.andrew.cmu.edu 5000\n");
  296.           return (MRESULT) NULL;
  297.         case IDM_CAPTURE:
  298.           {
  299.             FONTDLG     fnt;
  300.             char       s[256];
  301.         int i;
  302.         
  303.         for (i=1; i<=99; i++)
  304.           {
  305.         sprintf(s, "ch %d\n", i);
  306.         (*CommSpeak)(s);
  307.           }
  308.         
  309.             memset(&fnt,0,sizeof(FONTDLG));
  310.             hps = WinGetPS(hwnd);
  311.             fnt.cbSize = sizeof(FONTDLG);
  312.             fnt.hpsScreen = hps;
  313.             fnt.pszFamilyname = (UCHAR *)s;
  314.             fnt.usFamilyBufLen = sizeof(s);
  315.             WinFontDlg(HWND_DESKTOP,hwnd,&fnt);
  316.             WinReleasePS(hps);
  317.             return (MRESULT) NULL;
  318.           }
  319.  
  320.         case IDM_FLIP:
  321.           board.orient(' ');  // toggle it
  322.           WinInvalidateRegion(hBoard, NULLHANDLE, 0);
  323.       WinSendMsg(hStat, IDM_STAT, 0L, 0L);   // player names change
  324.           return (MRESULT) NULL;
  325.  
  326.         case IDM_ICSCMD_REFRESH:
  327.       {
  328.         char s[32];
  329.             if (board.is_valid())
  330.           sprintf(s,"\nrefresh %d\n", board.gameNum);
  331.         else
  332.           sprintf(s,"\nrefresh\n");
  333.         (*CommSpeak)(s);
  334.         return (MRESULT)NULL;
  335.       }
  336.  
  337.         case IDM_ICSCMD_FLAG:
  338.           (*CommSpeak)("\nflag\n");
  339.       strcpy(lastAction,"flag\n");
  340.           return (MRESULT)NULL;
  341.  
  342.         case IDM_SMALL:
  343.           setup(1);
  344.           return (MRESULT)NULL;
  345.  
  346.         case IDM_MEDIUM:
  347.           setup(2);
  348.           return (MRESULT)NULL;
  349.  
  350.         case IDM_LARGE:
  351.           setup(3);
  352.           return (MRESULT)NULL;
  353.  
  354.         case IDM_NEWBOARD:
  355.           board.init();
  356.           WinInvalidateRegion(hBoard, NULLHANDLE, 0);
  357.           return (MRESULT)NULL;
  358.  
  359.         case IDM_BOARD_REPLOT:
  360.           WinInvalidateRegion(hBoard, NULLHANDLE, 0);
  361.           return (MRESULT)NULL;
  362.  
  363.     case IDM_BOARD_LOCK:
  364.     case IDM_BOARD_UNLOCK:
  365.       WinPostMsg(hBoard, SHORT1FROMMP(mp1), 0L, 0L);
  366. if (ChildPID != 0) DosSendSignalException(ChildPID, XCPT_SIGNAL_INTR);
  367.       return (MRESULT)NULL;
  368.  
  369.         case IDM_TXQ_DUMP:
  370.           txq.Dump();
  371.           return (MRESULT)NULL;
  372.  
  373.         case IDM_TEST_CHALLENGE:
  374.           ProcessChallenge(hwnd, "Unrated blitz match 7 7 requested with abyss. (unreg.)");
  375.           return (MRESULT)NULL;
  376.  
  377.         case IDM_QUIT:
  378.           WinPostMsg( hwnd, WM_CLOSE, 0L, 0L );
  379.           return (MRESULT) NULL;
  380.         }
  381.  
  382.     default:
  383.       return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  384.     }
  385. }
  386.  
  387. LONG parse_colour(char *clrspec, LONG *default_colours)
  388. {
  389.   LONG  colour_value;
  390.   if (strcmp(clrspec, "blue")==0) return default_colours[CLR_BLUE];
  391.   if (strcmp(clrspec, "red")==0)  return default_colours[CLR_RED];
  392.   if (strcmp(clrspec, "pink")==0) return default_colours[CLR_PINK];
  393.   if (strcmp(clrspec, "green")==0)  return default_colours[CLR_GREEN];
  394.   if (strcmp(clrspec, "cyan")==0)  return default_colours[CLR_CYAN];
  395.   if (strcmp(clrspec, "yellow")==0)  return default_colours[CLR_YELLOW];
  396.   if (strcmp(clrspec, "neutral")==0)  return default_colours[CLR_NEUTRAL];
  397.   if (strcmp(clrspec, "darkgray")==0)  return default_colours[CLR_DARKGRAY];
  398.   if (strcmp(clrspec, "darkblue")==0)  return default_colours[CLR_DARKBLUE];
  399.   if (strcmp(clrspec, "darkred")==0)  return default_colours[CLR_DARKRED];
  400.   if (strcmp(clrspec, "darkpink")==0)  return default_colours[CLR_DARKPINK];
  401.   if (strcmp(clrspec, "darkgreen")==0)  return default_colours[CLR_DARKGREEN];
  402.   if (strcmp(clrspec, "darkcyan")==0)  return default_colours[CLR_DARKCYAN];
  403.   if (strcmp(clrspec, "brown")==0)  return default_colours[CLR_BROWN];
  404.   if (strcmp(clrspec, "palegray")==0)  return default_colours[CLR_PALEGRAY];
  405.   if (sscanf(clrspec, "%x", &colour_value) == 1)
  406.     return colour_value;
  407.   return default_colours[CLR_BACKGROUND];
  408. }
  409.  
  410. /*****************************************************************************/
  411. /* BoardProc - window method for BOARD                                    */
  412. /*                                                                           */
  413. /* Manages mouse-driven piece movement, game status display, and server      */
  414. /* message actions */
  415. /*****************************************************************************/
  416. MRESULT EXPENTRY BoardProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  417. {
  418.   static HPS    hps;                        /* presentation space handle */
  419.   static HDC    hdc;
  420.   static TID    tid1;
  421.   static char    locked = 1;
  422.   static short  fromRank, fromFile, toRank, toFile;
  423.  
  424.   switch( msg )
  425.     {
  426.     case WM_CREATE:
  427.       {
  428.         SIZEL sizl = {0,0};
  429.     LONG  alTable[16];    // rgb colour values
  430.         LONG  clr_wpc, clr_bpc, clr_wsc, clr_bsc;
  431.         hdc = WinOpenWindowDC(hwnd);
  432.         hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIT_MICRO |
  433.                            GPIA_ASSOC | GPIF_DEFAULT);
  434.     GpiQueryLogColorTable(hps, 0L, 0L, 16L, alTable);
  435.     clr_wpc = parse_colour(profile.wpc, alTable);
  436.     clr_bpc = parse_colour(profile.bpc, alTable);
  437.     clr_wsc = parse_colour(profile.wsc, alTable);
  438.     clr_bsc = parse_colour(profile.bsc, alTable);
  439.     alTable[CLR_WHITE_PIECE] = clr_wpc;
  440.     alTable[CLR_BLACK_PIECE] = clr_bpc;
  441.     alTable[CLR_WHITE_SQUARE] = clr_wsc;
  442.     alTable[CLR_BLACK_SQUARE] = clr_bsc;
  443.     GpiCreateLogColorTable(hps, 0L, LCOLF_CONSECRGB, 0L, 16L, alTable);
  444.         board.init();
  445.         return (MRESULT) FALSE;
  446.       }
  447.  
  448.     case WM_PAINT:
  449.       {
  450.         RECTL   rcInvalid;
  451.  
  452. /*      hps = WinBeginPaint (hwnd , 0L , &rcInvalid);*/
  453.         WinBeginPaint (hwnd, hps, &rcInvalid);
  454.         board.plot(hps);
  455.         WinEndPaint ( hps );
  456.         return (MRESULT) NULL;
  457.       }
  458.  
  459.     case WM_CLOSE:
  460.       WinReleasePS(hps);
  461.       WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  462.       fprintf(logfile,"BOARD method: goodbye\n");
  463.       return (MRESULT) NULL;
  464.  
  465.     case WM_BUTTON1DOWN:
  466.       {
  467.         fromFile = SHORT1FROMMP(mp1) / SQUARESIZE;
  468.         fromFile = (board.atTop=='B') ? fromFile : 7-fromFile;
  469.         fromRank = SHORT2FROMMP(mp1) / SQUARESIZE;
  470.         fromRank = (board.atTop=='B') ? fromRank : 7-fromRank;
  471.  
  472.         fprintf(logfile,"board: button down at (%d,%d)\n",  SHORT1FROMMP(mp1), SHORT2FROMMP(mp1));
  473.         return (MRESULT)FALSE;
  474.       }
  475.  
  476.     case WM_BUTTON1UP:
  477.       {
  478.         /* translate raster (x,y) to chessboard square */
  479.         /* as a function of SQUARESIZE and board.atTop */
  480.         toFile = SHORT1FROMMP(mp1) / SQUARESIZE;
  481.         toFile = (board.atTop=='B') ? toFile : 7-toFile;
  482.         toRank = SHORT2FROMMP(mp1) / SQUARESIZE;
  483.         toRank = (board.atTop=='B') ? toRank : 7-toRank;
  484.  
  485.         fprintf(logfile,"board: button up at (%d,%d)\n", SHORT1FROMMP(mp1), SHORT2FROMMP(mp1));
  486.         if (IN(toRank,0,7) && IN(toFile,0,7) &&
  487.             IN(fromRank,0,7) && IN(fromFile,0,7) &&
  488.             ! (toRank==fromRank && toFile == fromFile) &&
  489.             board.piece[fromRank][fromFile] != PI_EMPTY)
  490.           {
  491.             char        s[256];
  492.             char        pc = board.piece[fromRank][fromFile];
  493.  
  494.         fprintf(logfile,"locked = %d\n", locked);
  495.             if (!locked)
  496.               board.move(hps, fromRank, fromFile, toRank, toFile);
  497.             sprintf(s,"%c%d%c%d\n", fromFile+'a', fromRank+1,
  498.                                      toFile+'a', toRank+1);
  499.             if (pc == PI_W_KIN && strcmp(s,"e1g1\n")==0 ||
  500.                 pc == PI_B_KIN && strcmp(s,"e8g8\n")==0)
  501.               strcpy(s,"o-o\n");
  502.             else if (pc == PI_W_KIN && strcmp(s,"e1c1\n")==0 ||
  503.                      pc == PI_B_KIN && strcmp(s,"e8c8\n")==0)
  504.               strcpy(s,"o-o-o\n");
  505. if (ChildPID != 0) DosSendSignalException(ChildPID, XCPT_SIGNAL_INTR);
  506.             (*CommSpeak)(s);
  507.         strcpy(lastAction, s);
  508.             fromRank = fromFile = toRank = toFile = 8;   /* invalid */
  509.           }
  510.         return (MRESULT)FALSE;
  511.       }
  512.  
  513.     case WM_BUTTON2UP:
  514.       {
  515.         (*CommSpeak)(lastAction);
  516.         return (MRESULT)FALSE;
  517.       }
  518.  
  519.     case IDM_BOARD_UNLOCK:
  520.       locked = 0;
  521.       return (MRESULT)TRUE;
  522.     case IDM_BOARD_LOCK:
  523.       locked = 1;
  524.       return (MRESULT)TRUE;
  525.       
  526.     case IDM_BOARD_UPDATE:
  527.         board.update(hps);
  528.         return (MRESULT) NULL;
  529.  
  530.     default:
  531.       return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  532.     }
  533. }
  534.  
  535. /*****************************************************************************/
  536. /* text window processor
  537.  * cursor position in the i/o window is characterized by (row,col) where
  538.  * row 0 is the topmost row in the window and col 0 is the leftmost char
  539.  */
  540. MRESULT EXPENTRY TermProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  541. {
  542.   static HPS    hps;                        /* presentation space handle */
  543.   static HDC    hdc;
  544.   static TID    comInTid, timerTid;
  545.   static HWND    hTerm;
  546.   static char   is_new_line;    // state for IDM_DATA
  547.  
  548.   switch( msg )
  549.     {
  550.     case WM_CREATE:
  551.       {
  552.         ULONG   ulParmLen = 4;
  553.         static  timel_parm tp;
  554.         SIZEL   sizl = {0,0};
  555.         FATTRS  fat;
  556.  
  557.         /* get presentation space */
  558.         hdc = WinOpenWindowDC(hwnd);
  559.         hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIT_MICRO |
  560.                            GPIA_ASSOC | GPIF_DEFAULT);
  561.  
  562.         if (profile.CommMode==0)
  563.           {   // communicate through serial port
  564.         if (ComInit())    // nonzero = failed
  565.           {
  566.         WinSendMsg(hFrame, WM_CLOSE, 0L, 0L);
  567.         return (MRESULT)FALSE;
  568.           }
  569.         
  570.             DosCreateThread(&comInTid, (PFNTHREAD)(&TxComIn),
  571.                             (ULONG)hwnd, 0,4096);
  572.           }
  573.         else
  574.           {   // communicate through command session
  575.             SessionInit();
  576.           }
  577.  
  578.         DosGetDateTime(&keyDt);
  579.         tp.hwnd = hwnd;
  580.         tp.ms = 1000;
  581.         DosCreateThread(&timerTid, (PFNTHREAD)(&timel), (ULONG)&tp, 0, 4096);
  582.  
  583.         /* set font to Helvetica */
  584.         fat.usRecordLength = sizeof(FATTRS);
  585.         fat.fsSelection = 0;
  586.         fat.lMatch = 0L;
  587.         fat.idRegistry = 0;
  588.         fat.usCodePage = 850;
  589.         fat.lMaxBaselineExt = 16;
  590.         fat.lAveCharWidth = 9;
  591.         fat.fsType = 0;
  592.         fat.fsFontUse = FATTR_FONTUSE_NOMIX;
  593.         strcpy(fat.szFacename, "Helv");
  594.         GpiCreateLogFont(hps, (PSTR8)NULL, 1L, &fat);
  595.         GpiSetCharSet(hps, 1L);
  596.  
  597.         hTerm = WinCreateWindow(hwnd, WC_LISTBOX, (PSZ)"",
  598.                                     WS_VISIBLE | LS_NOADJUSTPOS,
  599.                                     0, 0, MW_X, MW_Y,
  600.                                     hwnd,
  601.                                     HWND_TOP, 306, NULL, NULL);
  602.     is_new_line = 1;   // initial state for text win
  603.  
  604.         return (MRESULT)FALSE;   /* IF YOU RETURN TRUE, BOOM */
  605.       }
  606.  
  607.     case WM_CHAR:
  608.       {
  609.         char s[100], c;
  610.         USHORT fsflags = SHORT1FROMMP(mp1);
  611.  
  612.         if (fsflags & KC_KEYUP)
  613.           return (MRESULT)FALSE;
  614.         if (c = CHAR1FROMMP(mp2))
  615.           {
  616.         fprintf(logfile,"term: char=%d %c\n", c, c);
  617.         
  618.             if (fsflags & KC_CTRL)
  619.               {
  620.                 if (c>='a' && c<='z')
  621.                   c = c - 'a' + 1;
  622.                 else
  623.                   return (MRESULT)FALSE;   /* bogus ctrl? */
  624.               }
  625.             s[0] = c;
  626.             s[1] = 0;
  627.             DosGetDateTime(&keyDt);
  628.             (*CommSpeak)(s);
  629.           }
  630.  
  631. /*    if (c=='~')
  632.           WinSendMsg(hTerm, LM_DELETEALL, 0L, 0L);*/
  633.  
  634.         // get out of the list box, restore normal focus
  635.         WinSetFocus(HWND_DESKTOP, hClient);
  636.  
  637.         return (MRESULT)TRUE;
  638.       }
  639.  
  640.     case IDM_COM_IN:
  641.       {
  642.         char            c, *stat, *s2;
  643.         char            *data = (char *)PVOIDFROMMP(mp1);
  644.         int             i;
  645.  
  646.         for (i=0; data[i]; i++)
  647.           {
  648.             c = data[i];
  649.  
  650.             if (c != 10)    // watch for EOL token
  651.                 txq.CharIn(c);
  652.             else
  653.               {
  654.                 s2 = txq.FinishLine();
  655.                 if ((stat = strstr(s2, "#@#")) != (char *)NULL)
  656.                   {             // status line
  657.                     board.msg_style_8(stat);
  658.                   }
  659.                 else if ((stat = strstr(s2, "requested with")) != (char *)NULL)
  660.                   {             // challenge
  661.                     ProcessChallenge(hwnd, s2);
  662.           }
  663.         
  664.                 else if (strstr(s2, "has been checkmated") != (char *)NULL)
  665.                   board.clockRun = FALSE;
  666.                 else if (strstr(s2, "Your opponent has run out of time") != (char *)NULL)
  667.                   board.clockRun = FALSE;
  668.               }
  669.           }
  670.  
  671.         /***********************/
  672.         /* update text monitor */
  673.         /***********************/
  674.         for (char * p=data;;)
  675.            {
  676.             char c, *q, t[256], *tp;
  677.         USHORT        n;
  678.         MPARAM        mp;
  679.  
  680.             if (is_new_line)   // last plot ended cleanly, so insert new line
  681.           {
  682.         // find newline or EOS.  build *t* filtering out crap.
  683.         for (q=p, tp=t; *q && *q!=10; q++)
  684.           {
  685.             if (*q == 13) ;
  686.             else if (*q == 8 && tp != t) tp--;
  687.             else *tp++ = *q;
  688.           }
  689.         *tp = 0;  // terminate u
  690.         c = *q;   // remember terminator from input
  691.         *q = 0;
  692.         
  693.         n = WinInsertLboxItem(hTerm, MPFROMSHORT(LIT_END),MPFROMP(t));
  694.         WinQueryLboxItemText(hTerm, n-1, (PSZ)t, sizeof(t));
  695.         if (strncmp(t, "#@#", 3) == 0 && n>=2)
  696.         {
  697.           WinDeleteLboxItem(hTerm, n-1);
  698.           WinDeleteLboxItem(hTerm, n-2);
  699.         }
  700.            }
  701.             else   // ended in mid-line, so append to last line
  702.           {
  703.         // load t with text of last item in terminal window
  704.              n = WinQueryLboxCount(hTerm) - 1;
  705.         WinQueryLboxItemText(hTerm, n, (PSZ)t, sizeof(t));
  706.  
  707.         // newline or EOS terminates input, in different states
  708.         // q scans input data, tp is output position
  709.         for (q=p, tp=t+strlen(t); *q && *q!=10; q++)
  710.           {
  711.             if (*q == 13) ;
  712.             else if (*q == 8 && tp != t) tp--;
  713.             else *tp++ = *q;
  714.           }
  715.         *tp = 0;  // terminate output
  716.         c = *q;   // remember terminator from input
  717.         
  718.           WinSetLboxItemText(hTerm, n, MPFROMP(t));
  719.           }
  720.  
  721.         is_new_line = (c == 10);
  722.         if (c)   // more data
  723.           p = q + 1;
  724.         else 
  725.         break;
  726.       }
  727.     
  728.     /* prune history buffer */
  729.     if (WinQueryLboxCount(hTerm) > TERM_SAVED_LINES)
  730.       {
  731.         while (WinDeleteLboxItem (hTerm, 0) > TERM_SAVED_LINES) ;
  732.       }
  733.     WinSendMsg(hTerm, LM_SETTOPINDEX, 
  734.            MPFROMSHORT(WinQueryLboxCount(hTerm)), 0L);
  735.  
  736.         free(data);
  737.         return (MRESULT)TRUE;
  738.       }
  739.  
  740.     case IDM_TIMEL:
  741.       {
  742.         DATETIME        dt;
  743.         int     roughMins;
  744.         DosGetDateTime(&dt);
  745.         roughMins = (keyDt.minutes - dt.minutes);
  746.         roughMins = (roughMins >= 0) ? roughMins : -roughMins;
  747.         if (roughMins > 3)
  748.       {
  749.         fprintf(logfile,"keepalive: sending blank\n");
  750.             (*CommSpeak)(" ");
  751.       }
  752.         return (MRESULT)FALSE;
  753.       }
  754.  
  755.     case WM_PAINT:
  756.       {
  757.         RECTL   rcInvalid;
  758.         WinBeginPaint (hwnd , hps, &rcInvalid );
  759.         WinFillRect (hps, &rcInvalid, CLR_WHITE);
  760.         WinEndPaint (hps);
  761.         return (MRESULT) NULL;
  762.       }
  763.  
  764.  
  765.     case WM_CLOSE:
  766.       WinDestroyWindow(hTerm);
  767.       WinReleasePS(hps);
  768.       DosKillThread(comInTid);
  769.       DosKillThread(timerTid);
  770.       WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  771.       return (MRESULT) NULL;
  772.  
  773.     default:
  774.       return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  775.     }
  776. }
  777. /*****************************************************************************/
  778. /*                             StatProc                                     */
  779. /*****************************************************************************/
  780. /*                                                                           */
  781. /* Manages mouse-driven piece movement, game status display, and server      */
  782. /* message actions  */
  783. /*****************************************************************************/
  784. MRESULT EXPENTRY StatProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  785. {
  786.   static HPS    hps;                        /* presentation space handle */
  787.   static HDC    hdc;
  788.   static TID    tid1;
  789.   static HWND   hMovelist, hGame, hBottom, hTop, hMove, hOnMove, hTest;
  790.   static HWND   hBFlag, hBResign, hBRefresh, hBDraw;
  791.   const  ULONG  backgnd = CLR_DARKGRAY;
  792.   APIRET        rc;
  793.  
  794.   switch( msg )
  795.     {
  796.     case WM_CREATE:
  797.       {
  798.         SIZEL sizl = {0,0};
  799.         static timel_parm tp;
  800.         tp.hwnd = hwnd;
  801.         tp.ms = 1000;
  802. /*        rc = DosCreateThread(&tid1, (PFNTHREAD)(&timel), (ULONG)&tp, 0, 4096);*/
  803.     WinStartTimer(hab, hwnd, ID_PMICS_STAT, 1000);
  804.  
  805.         hdc = WinOpenWindowDC(hwnd);
  806.         hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIT_MICRO |
  807.                            GPIA_ASSOC | GPIF_DEFAULT);
  808.  
  809. /*      WinLoadDlg(hwnd, hwnd, ScoreProc, NULLHANDLE, 100, 0);*/
  810.     GpiSetColor(hps, CLR_BLACK);
  811.     GpiSetBackColor(hps, backgnd);
  812. /*        hTest = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  813.                                 WS_VISIBLE | SS_GROUPBOX | SS_FGNDRECT |
  814.                    DT_LEFT | DT_VCENTER,
  815.                                 60, 280, 80, 40,
  816.                                 hwnd, HWND_TOP, 399, NULL, NULL);*/
  817.  
  818.         hGame = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  819.                                 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER,
  820.                                 70, 290, 60, 20,
  821.                                 hwnd, HWND_TOP, 300, NULL, NULL);
  822.         /**************/
  823.         /* text boxes */
  824.         /**************/
  825.         hTop = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  826.                                 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER,
  827.                                 10, 250, 180, 20,
  828.                                 hwnd, HWND_TOP, 301, NULL, NULL);
  829.         hBottom = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  830.                                 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER,
  831.                                 10, 210, 180, 20,
  832.                                 hwnd, HWND_TOP, 302, NULL, NULL);
  833.         hMove = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  834.                                 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER,
  835.                                 10, 150, 120, 20,
  836.                                 hwnd, HWND_TOP, 303, NULL, NULL);
  837.         hOnMove = WinCreateWindow(hwnd, WC_STATIC, (PSZ)"",
  838.                                 WS_VISIBLE | SS_TEXT | DT_LEFT | DT_VCENTER,
  839.                                 10, 120, 120, 20,
  840.                                 hwnd, HWND_TOP, 304, NULL, NULL);
  841.  
  842.         /***********/
  843.         /* buttons */
  844.         /***********/
  845.     hBFlag = WinCreateWindow(hwnd, WC_BUTTON, (PSZ)"flag",
  846.                WS_VISIBLE| BS_PUSHBUTTON| BS_NOPOINTERFOCUS,
  847.                200,290,50,25,
  848.                       hwnd, HWND_TOP, IDM_ICSCMD_FLAG, NULL, NULL);
  849.     hBResign = WinCreateWindow(hwnd, WC_BUTTON, (PSZ)"resign",
  850.                WS_VISIBLE| BS_PUSHBUTTON| BS_NOPOINTERFOCUS,
  851.                200,250,50,25,
  852.                       hwnd, HWND_TOP, IDM_ICSCMD_RESIGN, NULL, NULL);
  853.     hBRefresh = WinCreateWindow(hwnd, WC_BUTTON, (PSZ)"refresh",
  854.                WS_VISIBLE| BS_PUSHBUTTON| BS_NOPOINTERFOCUS,
  855.                200,210,50,25,
  856.                    hwnd, HWND_TOP, IDM_ICSCMD_REFRESH, NULL, NULL);
  857.     hBDraw = WinCreateWindow(hwnd, WC_BUTTON, (PSZ)"draw",
  858.                WS_VISIBLE| BS_PUSHBUTTON| BS_NOPOINTERFOCUS,
  859.                200,170,50,25,
  860.                       hwnd, HWND_TOP, IDM_ICSCMD_DRAW, NULL, NULL);
  861. /*    GpiSetColor(WinGetPS(hBResign), CLR_RED);  no effect, sigh */
  862.     
  863.  
  864.         /***********/
  865.         /* moves   */
  866.         /***********/
  867.         hMovelist = WinCreateWindow(hwnd, WC_LISTBOX, (PSZ)"",
  868.                                     WS_VISIBLE | LS_NOADJUSTPOS,
  869.                                     8, 20, SW_X-20, 85,
  870.                                     hwnd,
  871.                                     HWND_TOP, 305, NULL, NULL);
  872.  
  873.         return (MRESULT) FALSE;
  874.       }
  875.  
  876.     case WM_PAINT:
  877.       {
  878.         RECTL   rcInvalid;
  879.         hps = WinBeginPaint (hwnd , 0L , &rcInvalid);
  880.         WinFillRect (hps, &rcInvalid, CLR_DARKGRAY);
  881.         WinEndPaint (hps);
  882.         return (MRESULT) NULL;
  883.       }
  884.  
  885.     case WM_COMMAND:
  886.       {
  887.         switch(SHORT1FROMMP(mp1))
  888.       {
  889.       case IDM_ICSCMD_FLAG:   /* flag */
  890.         (*CommSpeak)("flag\n");
  891.         break;
  892.       case IDM_ICSCMD_RESIGN:
  893.         (*CommSpeak)("resign\n");
  894.         break;
  895.       case IDM_ICSCMD_DRAW:
  896.         (*CommSpeak)("draw\n");
  897.         break;
  898.       case IDM_ICSCMD_REFRESH:
  899.         {
  900.           char s[32];
  901.           if (board.is_valid())
  902.         sprintf(s,"\nrefresh %d\n", board.gameNum);
  903.           else
  904.         sprintf(s,"\nrefresh\n");
  905.           (*CommSpeak)(s);
  906.           return (MRESULT)NULL;
  907.         }
  908.       }
  909.       }
  910.       
  911.     case WM_TIMER:
  912.     case IDM_TIMEL:
  913.       {
  914.         char s[256];
  915.  
  916.         hps = WinGetPS(hwnd);
  917.         GpiSetColor(hps, CLR_BLACK);
  918.         GpiSetBackColor(hps, CLR_DARKGRAY);
  919.  
  920.         /*if ( ! board.clockRun)
  921.           return;*/
  922.         if (board.onMove != 'B')   // update WHITE clock
  923.           {
  924.             --board.timeW;
  925.             sprintf(s,"%s %d:%02d", board.playerW, board.timeW/60, board.timeW%60);
  926.             GpiSetColor(hps, (board.onMove != 'B' ? CLR_BLUE : CLR_BLACK));
  927.             WinSetWindowText(board.atTop=='B' ? hBottom : hTop, (PSZ)s);
  928.           }
  929.         else    // update BLACK clock
  930.           {
  931.             --board.timeB;
  932.             sprintf(s,"%s %d:%02d", board.playerB, board.timeB/60, board.timeB%60);
  933.             GpiSetColor(hps, (board.onMove == 'B' ? CLR_BLUE : CLR_BLACK));
  934.             WinSetWindowText(board.atTop=='B' ? hTop : hBottom, (PSZ)s);
  935.           }
  936.         WinReleasePS(hps);
  937.         return (MRESULT)0;
  938.       }
  939.  
  940.     case IDM_STAT:
  941.       {
  942.         char s[256];
  943.     int  n;
  944.  
  945.     GpiSetColor(hps, CLR_BLACK);
  946.     GpiSetBackColor(hps, backgnd);
  947.  
  948.         sprintf(s,"Game %d", board.gameNum);
  949.         WinSetWindowText(hGame, (PSZ)s);
  950.         WinSetWindowText(hTest, (PSZ)"Pmics");
  951.  
  952.         sprintf(s,"%s %d:%02d", board.playerW, board.timeW/60, board.timeW%60);
  953. /*      GpiSetColor(hps, (board.onMove != 'B' ? CLR_BLUE : CLR_BLACK));*/
  954.         WinSetWindowText(board.atTop=='B' ? hBottom : hTop, (PSZ)s);
  955.  
  956.         sprintf(s,"%s %d:%02d", board.playerB, board.timeB/60, board.timeB%60);
  957. /*      GpiSetColor(hps, (board.onMove == 'B' ? CLR_BLUE : CLR_BLACK));*/
  958.         WinSetWindowText(board.atTop=='B' ? hTop : hBottom, (PSZ)s);
  959.  
  960.         sprintf(s,"%s", board.lastMove);
  961.         WinSetWindowText(hMove, (PSZ)s);
  962.  
  963.         sprintf(s,"%s", board.onMove=='B'?"black to move":"white to move");
  964.         WinSetWindowText(hOnMove, (PSZ)s);
  965.  
  966.         // update the move list box
  967.     // moveNum==1 && onMove=='W' indicates initial position, not a move
  968.         if (! board.IsInitialPosition() &&
  969.         (board.moveNum != board.prevMoveNum ||
  970.         board.onMove  != board.prevOnMove))
  971.       {
  972.         board.prevMoveNum = board.moveNum;
  973.         board.prevOnMove = board.onMove;
  974.  
  975.         n = WinQueryLboxCount(hMovelist);
  976.         if (board.onMove == 'W')   // last move was black 
  977.           {
  978.             char oldMove[32];
  979.         WinSendMsg(hMovelist, LM_QUERYITEMTEXT, 
  980.                        MPFROM2SHORT(n-1,sizeof(oldMove)), (PSZ)oldMove);
  981.             sprintf(s,"%s %s", oldMove, board.lastMove);
  982.             WinSendMsg(hMovelist, LM_SETITEMTEXT,MPFROMSHORT(n-1), MPFROMP(s));
  983.             fprintf(scorefile, "%s\n", board.lastMove);
  984.           }
  985.         else   // last move was white
  986.           {
  987.             sprintf(s,"%d. %s", board.moveNum, board.lastMove);
  988.             WinSendMsg(hMovelist, LM_INSERTITEM, 
  989.                        MPFROMSHORT(LIT_END), MPFROMP(s));
  990.             fprintf(scorefile,"%d. %-8s ", board.moveNum, board.lastMove);
  991.           }
  992.         fprintf(logfile,"LIST: %d items\n", n);
  993.       }
  994.  
  995. {USHORT n = SHORT1FROMMP(WinSendMsg(hMovelist, LM_QUERYITEMCOUNT, 0L, 0L));
  996.     if (n>100)
  997.       while (SHORT1FROMMP(WinSendMsg(hMovelist, LM_DELETEITEM, 0L, 0L)) > 100) ;
  998.  n = SHORT1FROMMP(WinSendMsg(hMovelist, LM_QUERYITEMCOUNT, 0L, 0L));
  999.  WinPostMsg(hMovelist, LM_SETTOPINDEX, MPFROMLONG(n), 0L);
  1000. }
  1001.  
  1002.         return (MRESULT) FALSE;
  1003.       }
  1004.  
  1005.     case WM_CHAR:   // get out of the list box, restore normal focus
  1006.       WinSetFocus(HWND_DESKTOP, hClient);
  1007.       WinPostMsg(hTerm, msg, mp1, mp2);
  1008.       return (MRESULT)TRUE;
  1009.  
  1010.     case WM_CLOSE:
  1011.       DosKillThread(tid1);
  1012.       WinReleasePS(hps);
  1013.       WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  1014.       return (MRESULT) NULL;
  1015.  
  1016.     default:
  1017.       return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  1018.     }
  1019. }
  1020.  
  1021.  
  1022. MRESULT EXPENTRY ChallengeProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1023. {
  1024.   USHORT us;
  1025.   char         s[64];      // workarea
  1026.  
  1027.   switch(msg)
  1028.     {
  1029.     case WM_COMMAND:
  1030.       {
  1031.         MATCHPARMS *mat;    // wont work for multiple instantiations
  1032.         int min,sec;
  1033.         switch(us=SHORT1FROMMP(mp1))
  1034.       {
  1035.       case ID_MATCH_ACCEPT:
  1036.             mat = (MATCHPARMS *)WinQueryWindowPtr(hwnd, 0);
  1037.             WinQueryDlgItemText(hwnd, ID_MATCH_TIME, sizeof(s)-1, (PSZ)s);
  1038.             sscanf(s, "%d %d", &(mat->TimeMin), &(mat->TimeSec));
  1039.             WinDismissDlg(hwnd, us);
  1040.             break;
  1041.        case ID_MATCH_DECLINE:
  1042.       case ID_MATCH_IGNORE:
  1043.         WinDismissDlg(hwnd, us);
  1044.         break;
  1045.       }
  1046.       return (MRESULT)TRUE;
  1047.       }
  1048.  
  1049.     case WM_INITDLG:
  1050.       {
  1051.         MATCHPARMS *mat;    // wont work for multiple instantiations
  1052.         mat = (MATCHPARMS *)mp2;
  1053.         WinSetWindowPtr(hwnd, 0, (PVOID)mat);   
  1054.         fprintf(logfile,"challengeproc: mp1=%x mp2=%x\n", (ULONG)mp1, (ULONG)mp2);
  1055.     
  1056.     sprintf(s, "%s (%s)", mat->OppName, mat->OppRating);
  1057.     WinSetDlgItemText(hwnd, ID_MATCH_TEXT1, (PSZ)s);
  1058.     
  1059.     sprintf(s, "requests %s %s match", mat->RatedMode, mat->BlitzMode);
  1060.     WinSetDlgItemText(hwnd, ID_MATCH_TEXT2, (PSZ)s);
  1061.     
  1062.     sprintf(s, "%d %d", mat->TimeMin, mat->TimeSec);
  1063.     WinSetDlgItemText(hwnd, ID_MATCH_TIME, (PSZ)s);
  1064.     return (MRESULT)0;
  1065.       }      
  1066.  
  1067.     default:
  1068.       return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1069.     }
  1070. }
  1071.  
  1072.  
  1073. /*****************************************************************************/
  1074. /*****************************************************************************/
  1075. /*****************************************************************************/
  1076.  
  1077.                           /*************/
  1078.                           /* TermPut  */
  1079.                           /*************/
  1080. #define LMARG 4
  1081. #define BMARG 4
  1082. static void TermPut(HWND hwnd, HPS hps, char *s)
  1083. {
  1084.   static int    currow=0, curcol=0;
  1085.   static const int  maxrow = 10;
  1086.   static const int  maxcol = 80;
  1087.   static POINTL TermPos = {LMARG,BMARG};
  1088.  
  1089.   GpiMove(hps, &TermPos);
  1090.   for (; *s; s++)
  1091.     {
  1092.       RECTL     rectl;
  1093.       HRGN      hrgn;
  1094.  
  1095.       if (*s == 13) continue;   /* linefeed -- bound to CR, so ignore */
  1096.       if (*s == 10 || TermPos.x+8 > FW_X)
  1097.         {
  1098.           WinScrollWindow(hwnd, 0, (LONG)18, (PRECTL)NULL, (PRECTL)NULL,
  1099.                           (HRGN)NULLHANDLE, &rectl, 0);
  1100.           GpiSetColor(hps, CLR_WHITE);
  1101.           hrgn = GpiCreateRegion(hps, 1, &rectl);
  1102.           GpiPaintRegion(hps, hrgn);
  1103.           GpiDestroyRegion(hps, hrgn);
  1104.           TermPos.x = LMARG;
  1105.           GpiMove(hps, &TermPos);
  1106.       if (*s == 10) continue;   // linefeed is not plotted
  1107.         }
  1108.       GpiSetColor(hps, CLR_BLACK);
  1109.       GpiCharString(hps,1,(PCH)s);
  1110.     }
  1111.   GpiQueryCurrentPosition(hps, &TermPos);
  1112. }
  1113.  
  1114. /*****************************************************************************/
  1115. /* TxComIn - thread to monitor COM port                                      */
  1116. /*****************************************************************************/
  1117. /* thread does blocking reads against COM: and send data via window */
  1118. /* messages to the parent window as data arrives */
  1119. /*****************************************************************************/
  1120. static VOID TxComIn(ULONG dummy)
  1121. {
  1122.   ULONG         bytesRead;
  1123.   APIRET        rc;
  1124.   BYTE          *buf;
  1125.  
  1126.   fprintf(logfile,"TxComIn thread: hello\n"); fflush(logfile);
  1127.   WinInitialize(0);
  1128.   while (1)
  1129.     {
  1130.       buf = (BYTE *)malloc(2049);
  1131.       rc = DosRead(hcom, buf, 2048, &bytesRead);
  1132.       if (bytesRead == 0) continue;
  1133.       buf[bytesRead] = 0;
  1134.       fprintf(logfile,"TxComIn: rc=%d bytes= %d buf=%s\n", rc, bytesRead, buf);
  1135.       while (!WinPostMsg(hTerm, IDM_COM_IN, MPFROMP(buf), NULL))
  1136.     {
  1137.       fprintf(logfile,"ERROR: txcomin, winpostmsg; sleeping 250\n");
  1138.       DosSleep(250);   // let system catch its breath
  1139.     }
  1140.     }
  1141. }
  1142.  
  1143. /* do blocking reads against COM: and send data via windowing messages */
  1144. /* to the parent window as data arrives */
  1145. static VOID TxComOut(char *s)
  1146. {
  1147.   ULONG         cbWritten;
  1148.  
  1149.   DosGetDateTime(&keyDt);
  1150.   DosWrite(hcom, s, strlen(s), &cbWritten);
  1151.   fprintf(logfile,"TxComOut: %s\n",s);
  1152. }
  1153.  
  1154.  
  1155.  
  1156.  
  1157. static VOID _System PipeListen(ULONG readPipe)
  1158. {
  1159.   BYTE          *buf;
  1160.   ULONG         cbRead;
  1161.  
  1162.   fprintf(stderr, "listening to pipe %d\n", readPipe);
  1163.   WinInitialize(0);
  1164.   while(1)
  1165.     {
  1166.       buf = (BYTE *)malloc(PIPESIZE+1);
  1167.       DosRead(readPipe, (PVOID)buf, PIPESIZE, &cbRead);
  1168.       buf[cbRead] = 0;
  1169.       fprintf(logfile,"PipeListen: cbRead %d buf %s\n", cbRead, buf);
  1170.       while (!WinPostMsg(hTerm, IDM_COM_IN, MPFROMP(buf), NULL))
  1171.     {
  1172.       fprintf(logfile,"ERROR: txcomin, winpostmsg; sleeping 250\n");
  1173.       DosSleep(250);   // let system catch its breath
  1174.     }
  1175. /*      WinSendMsg(hTerm, IDM_COM_IN, MPFROMP(buf), NULL);*/
  1176.     }
  1177. }
  1178.  
  1179. static ULONG writePipe;   // set by SessionInit
  1180.  
  1181. static void PipeSpeak(char *s)
  1182. {
  1183.   ULONG cbWritten, n;
  1184.  
  1185.   DosGetDateTime(&keyDt);
  1186.   for (n=0; n<strlen(s); n++)
  1187.     if (s[n] == '\012')
  1188.       {
  1189.         DosWrite(writePipe, (PVOID)"\015", 1, &cbWritten);
  1190.         DosWrite(writePipe, (PVOID)(s+n), 1, &cbWritten);
  1191.       }
  1192.     else if (s[n] == '\015')
  1193.       {
  1194.         DosWrite(writePipe, (PVOID)(s+n), 1, &cbWritten);
  1195.         DosWrite(writePipe, (PVOID)"\012", 1, &cbWritten);
  1196.       }
  1197.     else
  1198.       DosWrite(writePipe, (PVOID)(s+n), 1, &cbWritten);
  1199.  
  1200. /*  DosWrite(writePipe, (PVOID)s, strlen(s), &cbWritten);*/
  1201. /*  fprintf(logfile,"PipeSpeak: %d %d %s\n", writePipe, cbWritten,s);*/
  1202. }
  1203.  
  1204.  
  1205. static int SessionInit()
  1206. {
  1207.   // DosExecPgm stuff
  1208.   CHAR          LoadError[CCHMAXPATH];
  1209.   RESULTCODES   ReturnCodes;
  1210.   ULONG         Pid;
  1211.  
  1212.   // pipe games stuff
  1213.   HFILE         hfOSave = -1, hfONew = HF_STDOUT;
  1214.   HFILE         hfOR, hfOW;
  1215.   HFILE         hfISave = -1, hfINew = HF_STDIN;
  1216.   HFILE         hfIR, hfIW;
  1217.   APIRET        rc;
  1218.  
  1219.   // misc
  1220.   ULONG         pidPipeListen;
  1221.  
  1222.  
  1223.   // redirect stdout
  1224.   DosDupHandle(HF_STDOUT, &hfOSave);  // save stdout
  1225.   DosCreatePipe(&hfOR, &hfOW, PIPESIZE);   // pipe for redirecting stdout
  1226.   DosDupHandle(hfOW, &hfONew);        // change stdout to the pipe
  1227.  
  1228.   // redirect stdin
  1229.   DosDupHandle(HF_STDIN, &hfISave);   // save stdin
  1230.   DosCreatePipe(&hfIR, &hfIW, PIPESIZE);   // pipe for redirecting stdin
  1231.   DosDupHandle(hfIR, &hfINew);        // switch stdin to the pipe
  1232.  
  1233.   // kick off a program with the gimmicked file handles
  1234.   rc = DosExecPgm(LoadError,            // object name buffer
  1235.                   sizeof(LoadError),    // length of object name buffer
  1236.                   EXEC_ASYNC,           // async/trace flags
  1237.                   (PSZ)"",              // argument string
  1238.                   (PSZ)0,               // environment string
  1239.                   &ReturnCodes,         // termination codes
  1240.                   (PSZ)profile.fcp);    // child program
  1241.  
  1242.   ChildPID = ReturnCodes.codeTerminate;   // pull out PID of child
  1243.   DosClose(hfOW);   // voodoo stuff the manual says to do
  1244.   DosClose(hfIR);
  1245.  
  1246.   hfONew = HF_STDOUT;
  1247.   DosDupHandle(hfOSave, &hfONew);    // bring stdout back
  1248.   hfINew = HF_STDIN;
  1249.   DosDupHandle(hfISave, &hfINew);    // bring stdin back
  1250.  
  1251.   if (rc != 0)
  1252.     return 1;    // DosExecPgm failed
  1253.  
  1254.   // initiate a task to Listen to the pipe
  1255.   DosCreateThread(&pidPipeListen, (PFNTHREAD)&PipeListen, (ULONG)hfOR, 0,4096);
  1256.   writePipe = hfIW;
  1257.  
  1258.   CommSpeak = &PipeSpeak;
  1259. //PipeSpeak("echo NOTE: your keystrokes will not echo until you hit ENTER!\n");
  1260.   
  1261.   // wait for the child to die
  1262. //DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &ReturnCodes, &Pid,
  1263. //             ReturnCodes.codeTerminate);
  1264.   return 0;   // show ok
  1265. }
  1266.  
  1267.  
  1268.  
  1269.  
  1270.                           /*************/
  1271.                           /* BoardPlot */
  1272.                           /*************/
  1273.  
  1274. void GAME::plot(HPS hps)
  1275. {
  1276.   BITMAPINFO2 pbmi;
  1277.   BITMAPINFO2 pbmi64;
  1278.   HBITMAP       hbm;
  1279.   POINTL        ptl[4] = {0,0,64,64,0,0,64,64};
  1280.   POINTL        ptl2[4] = {80,80};
  1281.   POINTL        p;
  1282.   int           rank, file;
  1283.  
  1284.   pbmi.cbFix    = 16;
  1285.   pbmi.cx       = 40;
  1286.   pbmi.cy       = 40;
  1287.   pbmi.cPlanes  = 1;
  1288.   pbmi.cBitCount        = 1;
  1289.  
  1290.   pbmi64.cbFix  = 16;
  1291.   pbmi64.cx     = 64;
  1292.   pbmi64.cy     = 64;
  1293.   pbmi64.cPlanes        = 1;
  1294.   pbmi64.cBitCount      = 1;
  1295.  
  1296. /*  GpiDrawBits(hps, bishop64, &pbmi64, 4, ptl, ROP_SRCCOPY, 0);
  1297.  
  1298.   hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&pbmi, CBM_INIT, (PBYTE)bishop40, &pbmi);
  1299.   WinDrawBitmap(hps, hbm, NULL, ptl2, CLR_BLACK, CLR_WHITE, DBM_NORMAL);*/
  1300.  
  1301.   for (rank=0; rank<8; rank++)
  1302.     for (file=0; file<8; file++)
  1303.       plot_piece(hps,piece[rank][file],rank,file);
  1304. }
  1305.  
  1306. void GAME::update(HPS hps)
  1307. {
  1308.   register int           rank, file;
  1309.  
  1310.   /* incremental update: opiece represents what is on the screen; piece */
  1311.   /* is the actual state of the board.  make the screen look like piece */
  1312.   /* and copy piece to opiece.  all updates (flip, statusproc, etc). are */
  1313.   /* made to piece. */
  1314.   for (rank=0; rank<8; rank++)
  1315.     for (file=0; file<8; file++)
  1316.       if (piece[rank][file] != opiece[rank][file] ||
  1317.       oAtTop != atTop)
  1318.         plot_piece(hps, piece[rank][file],rank,file);
  1319.   oAtTop = atTop;
  1320. }
  1321.  
  1322.  
  1323. void GAME::orient(char colour)
  1324. {
  1325.   if (colour == ' ')
  1326.     atTop = (atTop == 'B' ? 'W' : 'B');
  1327.   else
  1328.     atTop = colour;
  1329. }
  1330.                           /****************/
  1331.                           /*  plot_piece  */
  1332.                           /****************/
  1333.  
  1334. void GAME::plot_piece(HPS hps, char piece, char rank, char file)
  1335. {
  1336.   POINTL        p;
  1337.   SIZEL         sizl;
  1338.   RECTL         rect;
  1339.   HRGN          hrgn;
  1340.   char          rfile, rrank;    /* relative to board.atTop */
  1341.   static char   bits_fixed = 0;
  1342.  
  1343. /*fprintf(logfile,"plot: bits_byts:%d %x %x %x %x %x %x %x %x %x %x %x %x\n",
  1344. BITS_BYTES, pi_bits[1], pi_bits[2], pi_bits[3], pi_bits[4],
  1345. pi_bits[5], pi_bits[6], pi_bits[7], pi_bits[8], pi_bits[9],
  1346. pi_bits[10], pi_bits[11], pi_bits[12]);
  1347. fflush(logfile);*/
  1348.   if (!bits_fixed)
  1349.     {
  1350.       int i,j;
  1351.       struct
  1352.         {
  1353.           int b7:1,b6:1,b5:1,b4:1,b3:1,b2:1,b1:1,b0:1;
  1354.         } c1,c2;
  1355.       bits_fixed = 1;
  1356.       for (i=1; i<=6; i++)
  1357.         for (j=0; j<BITS_BYTES; j++)
  1358.           {
  1359.             memcpy(&c1,pi_bits[i]+j,1);
  1360.             c2.b7=c1.b0;
  1361.             c2.b6=c1.b1;
  1362.             c2.b5=c1.b2;
  1363.             c2.b4=c1.b3;
  1364.             c2.b3=c1.b4;
  1365.             c2.b2=c1.b5;
  1366.             c2.b1=c1.b6;
  1367.             c2.b0=c1.b7;
  1368.             memcpy(pi_bits[i]+j,&c2,1);
  1369.         }
  1370.     }
  1371.  
  1372.   sizl.cx = sizl.cy = SQUARESIZE;
  1373.   rfile = (board.atTop=='B') ? file : 7-file;
  1374.   rrank = (board.atTop=='B') ? rank : 7-rank;
  1375.  
  1376.   /* paint the square */
  1377.   rect.xLeft    = SQUARESIZE*rfile;
  1378.   rect.yBottom  = SQUARESIZE*rrank;
  1379.   rect.xRight   = rect.xLeft+SQUARESIZE;
  1380.   rect.yTop     = rect.yBottom+SQUARESIZE;
  1381. /*  hrgn          = GpiCreateRegion(hps, 1, &rect);
  1382.   GpiSetColor(hps, (rfile+rrank)&1 ? CLR_WHITE_SQUARE : CLR_BLACK_SQUARE);
  1383.   GpiPaintRegion(hps, hrgn);
  1384.   GpiDestroyRegion(hps, hrgn);*/
  1385.   // one call is simpler than 4 -- but what does the manual mean by
  1386.   // this function must only be used in draw mode (DM_DRAW)??
  1387.   WinFillRect(hps, &rect, (rfile+rrank)&1? CLR_WHITE_SQUARE: CLR_BLACK_SQUARE);
  1388.   
  1389.  
  1390.   /* paint the piece */
  1391.   if (piece != PI_EMPTY)
  1392.     {
  1393.       p.x = SQUARESIZE*rfile;
  1394.       p.y = SQUARESIZE*(rrank+1);
  1395.       GpiMove(hps, &p);
  1396.       GpiSetColor(hps, is_black(piece) ? CLR_BLACK_PIECE : CLR_WHITE_PIECE);
  1397.       /* set background color explicitly to fix (?) problem */
  1398.       /* of pieces appearing on a white background. */
  1399.       GpiSetBackColor(hps, (rfile+rrank)&1 ? CLR_WHITE_SQUARE : CLR_BLACK_SQUARE);
  1400.       GpiImage(hps, 0L, &sizl, BITS_BYTES, (PBYTE)(pi_bits[piece]));
  1401.     }
  1402.   opiece[rank][file] = piece;
  1403. }
  1404.                           /*************/
  1405.                           /* BoardInit */
  1406.                           /*************/
  1407.  
  1408.  
  1409. void GAME::init()
  1410. {
  1411.   static char ipos[8][8] =
  1412.     {
  1413.       PI_W_ROO,PI_W_KNI,PI_W_BIS,PI_W_QUE,PI_W_KIN,PI_W_BIS,PI_W_KNI,PI_W_ROO,
  1414.       PI_W_PAW,PI_W_PAW,PI_W_PAW,PI_W_PAW,PI_W_PAW,PI_W_PAW,PI_W_PAW,PI_W_PAW,
  1415.       PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,
  1416.       PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,
  1417.       PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,
  1418.       PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,PI_EMPTY,
  1419.       PI_B_PAW,PI_B_PAW,PI_B_PAW,PI_B_PAW,PI_B_PAW,PI_B_PAW,PI_B_PAW,PI_B_PAW,
  1420.       PI_B_ROO,PI_B_KNI,PI_B_BIS,PI_B_QUE,PI_B_KIN,PI_B_BIS,PI_B_KNI,PI_B_ROO
  1421.    };
  1422.   register int rank,file;
  1423.   for (rank=0; rank<8; rank++)
  1424.     for (file=0; file<8; file++)
  1425.       {
  1426.         piece[rank][file] = ipos[rank][file];
  1427.         opiece[rank][file] = PI_EMPTY;  // forces plot update
  1428.       }
  1429.   atTop = oAtTop = 'B';
  1430.   strcpy(playerW, "White");
  1431.   strcpy(playerB, "Black");
  1432.   timeW = 3600;
  1433.   timeB = 3600;
  1434.   onMove = 'W';
  1435.   clockRun = FALSE;
  1436. }
  1437.  
  1438.                           /*************/
  1439.                           /* BoardMove */
  1440.                           /*************/
  1441.  
  1442. void GAME::move(HPS hps,char rankFrom, char fileFrom, char rankTo, char fileTo)
  1443. {
  1444.   register char temp;   /* to handle error case of a1->a1, etc */
  1445.   temp = piece[rankFrom][fileFrom];
  1446.   piece[rankFrom][fileFrom] = PI_EMPTY;
  1447.   piece[rankTo][fileTo] = temp;
  1448.   plot_piece(hps, PI_EMPTY, rankFrom, fileFrom);
  1449.   plot_piece(hps, piece[rankTo][fileTo], rankTo, fileTo);
  1450. }
  1451.  
  1452.                           /*********/
  1453.                           /* TIMEL */
  1454.                           /*********/
  1455.  
  1456. static VOID timel(timel_parm *tp)
  1457. {
  1458.   WinInitialize(0);
  1459.   fprintf(logfile,"timel: ms=%d hwnd=%x\n", tp->ms, tp->hwnd);
  1460.   while (1)
  1461.     {
  1462.       DosSleep(tp->ms);
  1463.       WinPostMsg(tp->hwnd, IDM_TIMEL, NULL, NULL);
  1464.     }
  1465. }
  1466.  
  1467.  
  1468. void GAME::msg_style_8(char *s)
  1469. {
  1470.   char          *position, *s2;
  1471.   int   i, rank, file;
  1472.   struct _statMap
  1473.     {
  1474.       char startTrigger[3];
  1475.       char gameNum[3];
  1476.       char playerW[16];
  1477.       char delim1;
  1478.       char playerB[16];
  1479.       char delim2;
  1480.       char position[64];
  1481.       char moveNum[3];
  1482.       char onMove;
  1483.       char strW[2], strB[2];
  1484.       char timeW[5], timeB[5];
  1485.       char lastMoveAndTime[10];     // variable: o-o or Pa3-a4 followed by ' '
  1486.               // (mm:ss), so min length is 10 and may be greater
  1487.     } *statMap = (struct _statMap *)s;
  1488.   int min,sec;
  1489.  
  1490.   fprintf(logfile,"ProcessStatusMsg:%s\n", s);
  1491.  
  1492.   /* check for garbled data.  status line must be terminated and */
  1493.   /* the fixed portion must be present (up to but not including lastMove) */
  1494.   if ((s2 = strstr(s,"@#@")) == (char *)NULL ||   // must have terminator
  1495.       s2 - s < sizeof(*statMap)-sizeof(statMap->lastMoveAndTime))
  1496.     {
  1497.       int    gamenum;
  1498.       char     refMsg[32];
  1499.       static int errCnt = 0;
  1500.       fprintf(logfile, "ERROR: bad status line.  ignore and request refresh.\n");
  1501.       if (++errCnt > 10) return;   // prevent loop in case our method is bad
  1502.       sscanf(statMap->gameNum, "%3d", &gamenum);   // needed if mult monitor
  1503.       sprintf(refMsg, "\nrefresh %d\n", gamenum);
  1504.       (*CommSpeak)(refMsg);
  1505.       return;
  1506.     }
  1507.  
  1508.  
  1509.   sscanf(statMap->gameNum, "%3d", &gameNum);
  1510.   sscanf(statMap->playerW, "%16s", &playerW);
  1511.   sscanf(statMap->playerB, "%16s", &playerB);
  1512.   position = statMap->position;
  1513.   sscanf(statMap->moveNum, "%3d", &moveNum);
  1514.   onMove = statMap->onMove;
  1515.   sscanf(statMap->timeW, "%5d", &timeW);
  1516.   sscanf(statMap->timeB, "%5d", &timeB);
  1517.   sscanf(statMap->lastMoveAndTime, "%7s (%d:%d)", &lastMove, &min, &sec);
  1518.   lastMoveTime = min*60+sec;
  1519.   clockRun = TRUE;
  1520.   if (lastMove[1] == '/')   // strip that slash
  1521.     strcpy(lastMove+1, lastMove+2);
  1522.  
  1523.   if (IsInitialPosition())   // new game -- orient brd
  1524.     {
  1525.       time_t   ltime;
  1526.       char     time_buffer[32];
  1527.       board.prevMoveNum = 0;
  1528.       board.orient(statMap->delim1 == '*' ? 'B' : 'W');
  1529.       (*CommSpeak)("observe\n");
  1530.       // make header in score file in "PGN" format
  1531.       fprintf(scorefile, "\n\n[White \"%s\"]\n", playerW);
  1532.       fprintf(scorefile, "[Black \"%s\"]\n", playerB);
  1533.       time(<ime);
  1534.       strftime(time_buffer, sizeof(time_buffer), "%Y.%m.%d", 
  1535.                localtime(<ime));
  1536.       fprintf(scorefile, "[Date \"%s\"]\n\n", time_buffer);
  1537.     }
  1538.   
  1539.  
  1540.   for (i=0; i<64; i++)
  1541.     {
  1542.       file = i & 7;
  1543.       rank = i >> 3;
  1544.  
  1545.       switch(position[i])
  1546.         {
  1547.         case 'R':
  1548.           piece[rank][file] = PI_W_ROO;
  1549.           break;
  1550.         case 'N':
  1551.           piece[rank][file] = PI_W_KNI;
  1552.           break;
  1553.         case 'B':
  1554.           piece[rank][file] = PI_W_BIS;
  1555.           break;
  1556.         case 'Q':
  1557.           piece[rank][file] = PI_W_QUE;
  1558.           break;
  1559.         case 'K':
  1560.           piece[rank][file] = PI_W_KIN;
  1561.           break;
  1562.         case 'P':
  1563.           piece[rank][file] = PI_W_PAW;
  1564.           break;
  1565.         case 'r':
  1566.           piece[rank][file] = PI_B_ROO;
  1567.           break;
  1568.         case 'n':
  1569.           piece[rank][file] = PI_B_KNI;
  1570.           break;
  1571.         case 'b':
  1572.           piece[rank][file] = PI_B_BIS;
  1573.           break;
  1574.         case 'q':
  1575.           piece[rank][file] = PI_B_QUE;
  1576.           break;
  1577.         case 'k':
  1578.           piece[rank][file] = PI_B_KIN;
  1579.           break;
  1580.         case 'p':
  1581.           piece[rank][file] = PI_B_PAW;
  1582.           break;
  1583.         default:
  1584.           piece[rank][file] = PI_EMPTY;
  1585.           break;
  1586.         }
  1587.     }
  1588.   state = 1;            // board is valid now
  1589.   WinSendMsg(hBoard, IDM_BOARD_UPDATE, 0L, 0L);
  1590.   WinSendMsg(hStat, IDM_STAT, 0L, 0L);
  1591. /*  WinInvalidateRegion(hBoard, NULLHANDLE, 0);*/
  1592. }
  1593.  
  1594.  
  1595. /* Unrated blitz match 2 12 requested with glen. (unreg.)
  1596.    You may accept this with "accept glen", decline it with
  1597.    "decline glen", or propose different parameters.
  1598.    VCS % Creating unrated blitz match 2 12 with glen.
  1599. */
  1600. static void ProcessChallenge(HWND hwnd, char *s)
  1601. {
  1602.   char  *begin;
  1603.   MATCHPARMS mat;
  1604.   int    n, rating, n2;
  1605.   char  s2[100];
  1606.   HWND    hMatch;
  1607.  
  1608.   if ((begin=strstr(s,"Unrated")) == (char *)NULL &&
  1609.       (begin=strstr(s,"Rated")) == (char *)NULL)
  1610.     return;    // it parses not
  1611.   n = sscanf(begin, "%7s %8s match %d %d requested with %16s (%d)",
  1612.          mat.RatedMode,
  1613.          mat.BlitzMode,
  1614.          &mat.TimeMin, &mat.TimeSec,
  1615.          mat.OppName,
  1616.          &rating);   /* rating: (unreg) or (%d) */
  1617.   if (n<5)      // it parses not
  1618.     return;
  1619.   else if (n<6) // rating not converted
  1620.     strcpy(mat.OppRating, "UNR");
  1621.   else
  1622.     sprintf(mat.OppRating, "%d", rating);
  1623.   mat.OppName[strlen(mat.OppName)-1] = '\0';   // strip trailing '.'
  1624.   DosBeep(1380,100);    /* hertz, milliseconds -- mon dieu a simple utility */
  1625.  
  1626.   n2 = WinDlgBox(HWND_DESKTOP, hwnd, ChallengeProc, NULLHANDLE, ID_MATCH, (PVOID)&mat);
  1627.   switch (n2)
  1628.     {
  1629.     case ID_MATCH_ACCEPT:
  1630.       sprintf(s2, "\nobserve\nstyle 8\nmatch %s %d %d\n", mat.OppName, mat.TimeMin, mat.TimeSec);
  1631.       (*CommSpeak)(s2);
  1632.       break;
  1633.     case ID_MATCH_DECLINE:
  1634.       sprintf(s2, "\ndecline %s\n", mat.OppName);
  1635.       (*CommSpeak)(s2);
  1636.       break;
  1637.     }
  1638.  
  1639. #ifdef OLD
  1640.   sprintf(s2, "%s (%s) requests\n%s %s match at %d %d",
  1641.           matchOppName,
  1642.           matchOppRating,
  1643.           matchRatedMode,
  1644.           matchBlitzMode,
  1645.           matchTimeMin,
  1646.           matchTimeSec);
  1647.   switch(WinMessageBox(HWND_DESKTOP, hwnd,
  1648.                 (PSZ)s2,
  1649.                 (PSZ)"Match request",0,
  1650.                MB_MOVEABLE | MB_YESNOCANCEL | MB_QUERY | MB_DEFBUTTON1))
  1651.     {
  1652.     case MBID_YES:
  1653.       sprintf(s2, "\nobserve\nstyle 8\nmatch %s %d %d\n", matchOppName, matchTimeMin, matchTimeSec);
  1654.       (*CommSpeak)(s2);
  1655.       break;
  1656.     case MBID_NO:
  1657.       sprintf(s2, "\ndecline %s\n", matchOppName);
  1658.       (*CommSpeak)(s2);
  1659.       break;
  1660.     }
  1661. #endif
  1662. }
  1663.  
  1664.  
  1665. static void setup(int size)
  1666. {
  1667. extern char xs_s_r_bits[], xs_s_kt_bits[], xs_s_b_bits[], xs_s_q_bits[],
  1668.             xs_s_p_bits[], xs_s_k_bits[],
  1669.             solid_bishop_bits[], solid_knight_bits[], solid_pawn_bits[],
  1670.             solid_queen_bits[], solid_rook_bits[], solid_king_bits[],
  1671.             bishop_small_bits[], king_small_bits[], knight_small_bits[],
  1672.             pawn_small_bits[], queen_small_bits[], rook_small_bits[];
  1673.   switch(size)
  1674.     {
  1675.     case 1:   /* small */
  1676.       SQUARESIZE = 40;
  1677.       pi_bits[0] = (char *)NULL;
  1678.       pi_bits[1] = xs_s_r_bits;
  1679.       pi_bits[2] = xs_s_kt_bits;
  1680.       pi_bits[3] = xs_s_b_bits;
  1681.       pi_bits[4] = xs_s_q_bits;
  1682.       pi_bits[5] = xs_s_k_bits;
  1683.       pi_bits[6] = xs_s_p_bits;
  1684.       pi_bits[7] = xs_s_r_bits;
  1685.       pi_bits[8] = xs_s_kt_bits;
  1686.       pi_bits[9] = xs_s_b_bits;
  1687.       pi_bits[10] = xs_s_q_bits;
  1688.       pi_bits[11] = xs_s_k_bits;
  1689.       pi_bits[12] = xs_s_p_bits;
  1690.       break;
  1691.     case 2:   /* medium */
  1692.       SQUARESIZE = 64;
  1693.       pi_bits[0] = (char *)NULL;
  1694.       pi_bits[1] = rook_small_bits;
  1695.       pi_bits[2] = knight_small_bits;
  1696.       pi_bits[3] = bishop_small_bits;
  1697.       pi_bits[4] = queen_small_bits;
  1698.       pi_bits[5] = king_small_bits;
  1699.       pi_bits[6] = pawn_small_bits;
  1700.       pi_bits[7] = rook_small_bits;
  1701.       pi_bits[8] = knight_small_bits;
  1702.       pi_bits[9] = bishop_small_bits;
  1703.       pi_bits[10] = queen_small_bits;
  1704.       pi_bits[11] = king_small_bits;
  1705.       pi_bits[12] = pawn_small_bits;
  1706.       break;
  1707.     case 3:   /* large */
  1708.       SQUARESIZE = 80;
  1709.       pi_bits[0] = (char *)NULL;
  1710.       pi_bits[1] = solid_rook_bits;
  1711.       pi_bits[2] = solid_knight_bits;
  1712.       pi_bits[3] = solid_bishop_bits;
  1713.       pi_bits[4] = solid_queen_bits;
  1714.       pi_bits[5] = solid_king_bits;
  1715.       pi_bits[6] = solid_pawn_bits;
  1716.       pi_bits[7] = solid_rook_bits;
  1717.       pi_bits[8] = solid_knight_bits;
  1718.       pi_bits[9] = solid_bishop_bits;
  1719.       pi_bits[10] = solid_queen_bits;
  1720.       pi_bits[11] = solid_king_bits;
  1721.       pi_bits[12] = solid_pawn_bits;
  1722.       break;
  1723.     }
  1724. }
  1725.  
  1726.  
  1727.                  /*****************/
  1728.                  /* CLASS   TXQ   */
  1729.                  /*****************/
  1730. TXQ::TXQ()
  1731. {
  1732.   headl = headc = taill = tailc = 0;    // empty queue
  1733. }
  1734.  
  1735. void TXQ::CharIn(char c)
  1736. {
  1737.   if (c == 015) return;    // discard CR, no one depends on it
  1738.   if (tailc != queuec)     // if line overflow, discard text
  1739.     buf[taill][tailc++] = c;
  1740.   else
  1741.     fprintf(logfile,"TXQ: OVERFLOW\n");
  1742. }
  1743.  
  1744. char * TXQ::FinishLine()
  1745. {
  1746.   char *p = buf[taill];
  1747.  
  1748.   if (tailc == queuec) tailc--;   // force in line terminator
  1749.   buf[taill][tailc] = '\0';
  1750.   fprintf(logfile,"finishline %d %s\n", tailc, p);
  1751.   taill = (taill+1) % queuel;
  1752.   tailc = 0;
  1753.   if (taill == headl)    // full queue -- discard oldest line
  1754.     headl = (headl+1) % queuel;
  1755.   return p;
  1756. }
  1757.  
  1758. char * TXQ::CurLine()   // current line as is
  1759. {
  1760.   buf[taill][(tailc==queuec) ? tailc-1 : tailc] = '\0';
  1761.   return buf[taill];
  1762. }
  1763.  
  1764. char * TXQ::WinLine(int n)   // line n relative to window of last winl lines
  1765. {
  1766.   buf[taill][(tailc==queuec) ? tailc-1 : tailc] = '\0';
  1767.   return buf[(taill+queuel-winl+n) % queuel];
  1768. }
  1769.  
  1770. char * TXQ::BufLine(int n)   // line n relative to head (0=first)
  1771. {
  1772.   char *p;
  1773.  
  1774.   buf[taill][(tailc==queuec) ? tailc-1 : tailc] = '\0';
  1775.   p = buf[(headl+n) % queuel];    // guaranteed within the queue, somewhere
  1776.     return p;
  1777. }
  1778.  
  1779. void TXQ::Dump()
  1780. {
  1781.   int i;
  1782.  
  1783.   fprintf(logfile,"Text queue dump\n===============\n");
  1784.   fprintf(logfile,"taill %d tailc %d headl %d headc %d\n",
  1785.           taill, tailc, headl, headc);
  1786.   for (i = headl; i != taill; i = (i+1) % queuel)
  1787.     fprintf(logfile, "%02d: %s\n", i, buf[i]);
  1788.   if (headl != taill)    // that would be empty queue
  1789.     {
  1790.       buf[taill][(tailc==queuec) ? tailc-1 : tailc] = '\0';
  1791.       fprintf(logfile, "taill: %s\n", buf[taill]);
  1792.     }
  1793. }
  1794.  
  1795.  
  1796. #define COMOPEN(s) \
  1797.       DosOpen((PSZ)(s), &hcom, &crap, 0, FILE_NORMAL, \
  1798.            FILE_OPEN, OPEN_ACCESS_READWRITE | OPEN_FLAGS_FAIL_ON_ERROR | \
  1799.           OPEN_SHARE_DENYREADWRITE, (PEAOP2) NULL)
  1800.  
  1801. static char ComInit() 
  1802. {
  1803.     APIRET rc;
  1804.     DCBINFO     dcbinfo;        /* Device control block for Ioctl 53H, 73H */
  1805.     LINECONTROL lnctlBuf;
  1806.     ULONG       ulParmLen;
  1807.     ULONG       crap;
  1808.     char    comfile[5];
  1809.     int        comnum;
  1810.  
  1811.     /**********************************************************************/
  1812.     /* Get File Handle hcom for COM port (shared read/write access)       */
  1813.     /* if /Cn was specified then use com port n.  Otherwise try com ports */
  1814.     /* 1-4 in turn and use the first one that opens succesfully.          */
  1815.     /**********************************************************************/
  1816.     if (profile.ComPort != 0)
  1817.       {
  1818.     sprintf(comfile, "COM%1d", profile.ComPort);
  1819.         rc = COMOPEN(comfile);
  1820.         fprintf(logfile,"cominit: open %s rc=%d\n", comfile, rc);
  1821.     if (rc)
  1822.       {
  1823.         WinMessageBox(HWND_DESKTOP, hClient, 
  1824.                           (PSZ)"Unable to open specified COM port",
  1825.                           (PSZ)"Init failed", 0, MB_ICONEXCLAMATION | MB_OK);
  1826.         return 1;   // failed
  1827.         }
  1828.       }
  1829.     else    
  1830.       {
  1831.         for (comnum = 1; comnum <= 4; comnum++)
  1832.       {
  1833.             sprintf(comfile, "COM%1d", comnum);
  1834.             rc = COMOPEN(comfile);
  1835.             fprintf(logfile,"cominit: open %s rc=%d\n", comfile, rc);
  1836.         if (rc == 0)
  1837.           break;
  1838.       }
  1839.     if (rc)
  1840.       {
  1841.         WinMessageBox(HWND_DESKTOP, hClient, 
  1842.               (PSZ)"Unable to open any COM port. "
  1843.         "Try specifying your COM port number with /Cn"
  1844.         " and the baud rate with /Pnnn, e.g.\n"
  1845.         "    start pmics /c2 /p2400\n"
  1846.         "to use COM2 at 2400 baud",
  1847.               (PSZ)"Init failed", 0, MB_ICONEXCLAMATION | MB_OK);
  1848.         return 1;   // failed
  1849.           }
  1850.       }
  1851.         
  1852. #ifdef CRAP
  1853.     /* Call Category 1 Function 42H   Set Line Characteristics */
  1854.     lnctlBuf.bDataBits  = 8;
  1855.     lnctlBuf.bParity    = 0;
  1856.     lnctlBuf.bStopBits  = 1;    /* IDD_ONESTOP = 20 */
  1857.     ulParmLen = sizeof(LINECONTROL);
  1858.     rc = DosDevIOCtl(hcom, IOCTL_ASYNC, ASYNC_SETLINECTRL, &lnctlBuf, sizeof(LINECONTROL), &ulParmLen, NULL, 0, (PULONG)NULL);
  1859.     fprintf(logfile,"line characteristics rc=%d\n", rc); fflush(stdout);
  1860. #endif
  1861.  
  1862.     /* Call Category 1 Function 73H   Query Device Control Block */
  1863.     ulParmLen = 0;
  1864.     crap = sizeof(DCBINFO);
  1865.  
  1866.     rc = DosDevIOCtl(hcom, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, &ulParmLen, &dcbinfo, sizeof(DCBINFO), &crap);
  1867.     fprintf(logfile,"query dcb rc=%d crap=%d\n"
  1868.                "  WriteTimeout %4x\n"
  1869.                "  ReadTimeout  %4x\n"
  1870.                "  flags1 %2x flags2 %x flags3 %x\n",
  1871.                rc, crap,
  1872.                dcbinfo.usWriteTimeout,
  1873.                dcbinfo.usReadTimeout,
  1874.                dcbinfo.fbCtlHndShake,
  1875.                dcbinfo.fbFlowReplace,
  1876.                dcbinfo.fbTimeout); fflush(stdout);
  1877.  
  1878.     /* Call Category 1 Function 41H   Set Baud Rate */
  1879.     ulParmLen = 4;
  1880.     rc = DosDevIOCtl(hcom, IOCTL_ASYNC, ASYNC_SETBAUDRATE, &profile.ComBaud, 
  1881.                  sizeof(profile.ComBaud), &ulParmLen, NULL, 0, (PULONG)NULL);
  1882.     fprintf(logfile,"baud rate set rc=%d\n", rc); fflush(stdout);
  1883.  
  1884.     /**********************************************************************/
  1885.     /* Use wait-for-input mode so the COM thread can do blocking reads    */
  1886.     /* against hcom until any data is available.                          */
  1887.     /**********************************************************************/
  1888.     dcbinfo.fbTimeout           &= ~(0x06);     /* Clear bits, then set */
  1889.     dcbinfo.fbTimeout           |= MODE_WAIT_READ_TIMEOUT;
  1890.     dcbinfo.usReadTimeout       = -1;           /* Never! */
  1891.  
  1892.     /* Call Category 1 Function 53H   Set Device Control Block */
  1893.     ulParmLen = sizeof(DCBINFO);
  1894.     rc = DosDevIOCtl(hcom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcbinfo, sizeof(DCBINFO), &ulParmLen, NULL, 0, (PULONG)NULL);
  1895.     fprintf(logfile,"set dcb rc = %d unparmlen=%d\n", rc, ulParmLen);
  1896.     CommSpeak = &TxComOut;
  1897.  
  1898.     if (profile.DialString[0])    // user specified init string 
  1899.       { 
  1900.         (*CommSpeak)(profile.DialString);
  1901.     (*CommSpeak)("\015");
  1902.       }
  1903.     else   // send a default modem init string
  1904.       (*CommSpeak)("ATE1\015");   // tell modem to echo commands
  1905.     return 0;                // show successful open
  1906. }
  1907.  
  1908.  
  1909. void main(int argc, char **argv)
  1910. {
  1911.     HMQ  hmq;                               /* message queue handle */
  1912.     QMSG qmsg;                              /* message from message queue */
  1913.     ULONG flCreate;                         /* window creation control flags*/
  1914.     SWP     swp;
  1915.     int  n;
  1916.     RECTL rcl;
  1917.  
  1918.     logfile = fopen(LOG_FILE, "w");           // debug log   
  1919.     scorefile = fopen(SCORE_FILE, "a");    // game score
  1920.  
  1921.     /*******************/
  1922.     /* parse arguments */
  1923.     /*******************/
  1924.     profile.BoardSize = 1;      // small
  1925.     profile.CommMode = 0;       // preset serial port
  1926.     profile.ComPort = 0;        // COM port number (preset search mode)
  1927.     profile.ComBaud = 9600;    // COM port baud rate
  1928.     profile.WinX = profile.WinY = 0;   // show default window dimensions
  1929.     profile.DialString[0] = 0;  // no dialstring by default
  1930.     profile.wsc = "green";
  1931.     profile.bsc = "brown";
  1932.     profile.wpc = "white";
  1933.     profile.bpc = "black";
  1934.     profile.fcp = "CMD.EXE";
  1935.     for (n=1; n<argc; n++)
  1936.       {
  1937.         if (*argv[n] != '/') continue;
  1938.  
  1939.     if (strcmp(argv[n]+1, "wsc") == 0 && ++n < argc)
  1940.       profile.wsc = argv[n];
  1941.  
  1942.     else if (strcmp(argv[n]+1, "bsc") == 0 && ++n < argc)
  1943.       profile.bsc = argv[n];
  1944.  
  1945.     else if (strcmp(argv[n]+1, "wpc") == 0 && ++n < argc)
  1946.       profile.wpc = argv[n];
  1947.  
  1948.     else if (strcmp(argv[n]+1, "bpc") == 0 && ++n < argc)
  1949.       profile.bpc = argv[n];
  1950.  
  1951.     else if (strcmp(argv[n]+1, "fcp") == 0 && ++n < argc)
  1952.       profile.fcp = argv[n];
  1953.  
  1954.         else switch (argv[n][1])
  1955.           {
  1956.           case 'B': case 'b':     // board size
  1957.             sscanf(argv[n]+2, "%d", &profile.BoardSize);
  1958.             break;
  1959.           case 'c': case 'C':     // COM port number to use
  1960.             if (sscanf(argv[n]+2, "%d", &profile.ComPort) != 1)
  1961.           profile.ComPort = 0;
  1962.             profile.CommMode = 0;
  1963.             break;
  1964.       case 'P': case 'p':    // COM port parameters /P9600,8,N,1
  1965.             sscanf(argv[n]+2, "%d", &profile.ComBaud);
  1966.         break;
  1967.       case 'S': case 's':     // use session instead of comm port
  1968.         profile.CommMode = 1;
  1969.         break;
  1970.           case 'X': case 'x':     // X dimension 
  1971.             sscanf(argv[n]+2, "%d", &profile.WinX);
  1972.             break;
  1973.           case 'Y': case 'y':     // Y dimension
  1974.             sscanf(argv[n]+2, "%d", &profile.WinY);
  1975.             break;
  1976.           case 'D': case 'd':     // Dial string for modem
  1977.         if (argv[n][2] != '"')   // simple non-quoted string
  1978.           strcpy(profile.DialString, argv[n]+2);
  1979.         else
  1980.           {
  1981.                 char *delim;
  1982.         
  1983.               strcpy(profile.DialString, argv[n]+3);
  1984.         while (++n < argc)
  1985.           if ((delim = strstr(profile.DialString, "\"")) != NULL)
  1986.             {
  1987.               *delim = '\0';
  1988.               break;
  1989.             }
  1990.           else
  1991.               strcat(profile.DialString, argv[n]);
  1992.           }
  1993.           }
  1994.       }
  1995.     fprintf(logfile,"dialstring: %s\n", profile.DialString);
  1996.     if (profile.WinX == 0)   // choose default based on board size
  1997.       {
  1998.         USHORT sizes[] = {600, 800, 1024};
  1999.     profile.WinX = sizes[profile.BoardSize-1];
  2000.       }
  2001.     if (profile.WinY == 0)   // choose default based on board size
  2002.       {
  2003.         USHORT sizes[] = {600, 768, 1024};
  2004.     profile.WinY = sizes[profile.BoardSize-1];
  2005.       }
  2006.     FW_X = profile.WinX;
  2007.     FW_Y = profile.WinY;
  2008.         
  2009.     setup(profile.BoardSize);
  2010.  
  2011.     hab = WinInitialize(0);
  2012.  
  2013.     hmq = WinCreateMsgQueue( hab, 0 );
  2014.  
  2015.     WinRegisterClass(                   /* Register window class */
  2016.        hab,                             /* Anchor block handle */
  2017.        (PSZ)WCP_MAIN,                   /* Window class name */
  2018.        FrameProc,                    /* Address of window procedure */
  2019.        CS_SIZEREDRAW,                   /* No special Class Style */
  2020.        0                                /* No extra window words */
  2021.        );
  2022.     WinRegisterClass(                   /* Register window class */
  2023.        hab,                             /* Anchor block handle */
  2024.        (PSZ)WCP_BOARD,                  /* Window class name */
  2025.        BoardProc,                    /* Address of window procedure */
  2026.        0,                               /* No special Class Style */
  2027.        0                                /* No extra window words */
  2028.        );
  2029.     WinRegisterClass(                   /* Register window class */
  2030.        hab,                             /* Anchor block handle */
  2031.        (PSZ)WCP_MSG,                    /* Window class name */
  2032.        TermProc,                       /* Address of window procedure */
  2033.        0,                               /* No special Class Style */
  2034.        0                                /* No extra window words */
  2035.        );
  2036.     WinRegisterClass(                   /* Register window class */
  2037.        hab,                             /* Anchor block handle */
  2038.        (PSZ)WCP_STAT,                   /* Window class name */
  2039.        StatProc,                        /* Address of window procedure */
  2040.        0,                               /* No special Class Style */
  2041.        0                                /* No extra window words */
  2042.        );
  2043.  
  2044. /**************/
  2045.     flCreate = FCF_SYSMENU  | FCF_SIZEBORDER | FCF_TITLEBAR | FCF_ICON |
  2046.                FCF_MINMAX   | FCF_TASKLIST | FCF_MENU | FCF_ACCELTABLE;
  2047.  
  2048.     hFrame = WinCreateStdWindow(
  2049.                  HWND_DESKTOP,          /* Desktop window is parent */
  2050.                  WS_VISIBLE,            /* Frame Class Style */
  2051.                  &flCreate,             /* Frame creation flags */
  2052.                  (PSZ)WCP_MAIN,         /* Client window class name */
  2053.                  (PSZ)APP_TITLE,        /* 0=Use EXE name as title */
  2054.                  0L,                    /* No special class style */
  2055.                  NULLHANDLE,                    /* Resource is in .EXE file */
  2056.                  ID_PMICS,                      /* Frame window identifier */
  2057.                  &hClient               /* Client window handle returned */
  2058.                  );
  2059.     WinSetWindowPos(hFrame, 0L, 0, 0, FW_X, FW_Y, SWP_SIZE);
  2060.     WinQueryWindowPos(hFrame, &swp);   // how big is it including borders?
  2061.     WinSetWindowPos(hFrame, 0L,
  2062.          (SHORT)0,            // position
  2063.          (SHORT)(WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - swp.cy),
  2064.                     0, 0, SWP_MOVE);
  2065.     WinQueryWindowRect(hClient, &rcl);    // how big is the client window?
  2066.     fprintf(logfile,"client: %d %d %d %d\n", rcl.xLeft, rcl.yBottom,
  2067.        rcl.xRight, rcl.yTop);
  2068.     CW_X = rcl.xRight;
  2069.     CW_Y = rcl.yTop;
  2070.  
  2071. /**********/
  2072. /* parent was hFrame in other method */
  2073.     hBoard = WinCreateWindow(hClient,(PSZ)WCP_BOARD, (PSZ)NULL, WS_VISIBLE,
  2074.                               FW_BW_X, FW_BW_Y, BW_X, BW_Y,
  2075.                               NULLHANDLE, HWND_TOP, ID_PMICS_BOARD,NULL, NULL);
  2076.     if (hBoard == NULLHANDLE)
  2077.       {
  2078.         fprintf(logfile, "board window not created: error %x\n",
  2079.                 WinGetLastError(hab)), fclose(logfile); goto quit;
  2080.       }
  2081.  
  2082.     hTerm = WinCreateWindow(hClient, (PSZ)WCP_MSG, (PSZ)NULL, WS_VISIBLE,
  2083.                               FW_MW_X, FW_MW_Y, MW_X, MW_Y,
  2084.                               NULLHANDLE, HWND_TOP, ID_PMICS_MSG, NULL, NULL);
  2085.     if (hTerm == NULLHANDLE)
  2086.       {
  2087.         fprintf(logfile, "msg window not created: error %x\n",
  2088.                 WinGetLastError(hab)), fclose(logfile); goto quit;
  2089.       }
  2090.  
  2091.     hStat = WinCreateWindow(hClient, (PSZ)WCP_STAT, (PSZ)NULL, WS_VISIBLE,
  2092.                               FW_SW_X, FW_SW_Y, SW_X, SW_Y,
  2093.                               NULLHANDLE, HWND_TOP, ID_PMICS_STAT, NULL, NULL);
  2094.     if (hStat == NULLHANDLE)
  2095.       {
  2096.         fprintf(logfile, "stat window not created: error %x\n",
  2097.                 WinGetLastError(hab)), fclose(logfile); goto quit;}
  2098.  
  2099.     while ( WinGetMsg( hab, &qmsg, 0, 0, 0 ) != FALSE )
  2100.         WinDispatchMsg( hab, &qmsg );
  2101.  
  2102.   quit:
  2103.     if (hStat != NULLHANDLE) WinDestroyWindow (hStat);
  2104.     if (hTerm != NULLHANDLE) WinDestroyWindow (hTerm);
  2105.     if (hBoard != NULLHANDLE) WinDestroyWindow (hBoard);
  2106.     if (hFrame != NULLHANDLE) WinDestroyWindow (hFrame);
  2107.     WinDestroyMsgQueue (hmq);
  2108.     WinTerminate (hab);
  2109.     fclose(logfile);
  2110.     fclose(scorefile);
  2111. }
  2112.  
  2113.  
  2114.  
  2115.  
  2116.  
  2117.  
  2118.  
  2119. #ifdef DEAD_CODE
  2120.           WinMessageBox(HWND_DESKTOP, hwnd,
  2121.                         (PSZ)"SERVER LOGIN message received",
  2122.                         (PSZ)"Menu item selection",0,
  2123.                         MB_MOVEABLE | MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2);
  2124.  
  2125.     FRAMECDATA  fcdata = {sizeof(FRAMECDATA),
  2126.                            FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  2127.               FCF_MINMAX | FCF_TASKLIST | FCF_MENU | FCF_ACCELTABLE,
  2128.                              NULLHANDLE, ID_PMICS};
  2129.     hFrame = WinCreateWindow(HWND_DESKTOP, WC_FRAME, APP_TITLE, WS_VISIBLE,
  2130.                              0,0,FW_X,FW_Y,
  2131.                              NULLHANDLE, HWND_TOP, ID_PMICS, &fcdata, NULL);
  2132.     if (hFrame == NULLHANDLE)
  2133.       {
  2134.         fprintf(logfile, "frame window not created: error %x\n",
  2135.                 WinGetLastError(hab)), fclose(logfile); goto quit;
  2136.       }
  2137.  
  2138. BOOL DrawLine(HPS hps, LONG x1, LONG y1, LONG x2, LONG y2)
  2139. {
  2140.   POINTL        ptl;
  2141.   ptl.x = x1;
  2142.   ptl.y = y1;
  2143.   GpiMove(hps, &ptl);
  2144.   ptl.x = x2;
  2145.   ptl.y = y2;
  2146.   return (GpiLine(hps, &ptl) == GPI_OK);
  2147. }
  2148.  
  2149. /*      WinMessageBox(HWND_DESKTOP, hwnd,
  2150.         (PSZ)"CREATE message received!!!",
  2151.         (PSZ)"CREATE message",0,
  2152.                     MB_MOVEABLE | MB_YESNOCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2);*/
  2153.  
  2154.  
  2155.     flCreate = FCF_SYSMENU  | FCF_SIZEBORDER    | FCF_TITLEBAR   |
  2156.                FCF_MINMAX   | FCF_MENU | FCF_TASKLIST ;
  2157.  
  2158.  
  2159.     hFrame = WinCreateStdWindow(
  2160.                  HWND_DESKTOP,          /* Desktop window is parent */
  2161.                  WS_VISIBLE,            /* Frame Class Style */
  2162.                  &flCreate,             /* Frame creation flags */
  2163.                  WCP_MAIN,              /* Client window class name */
  2164.                  "PMICS",               /* 0=Use EXE name as title */
  2165.                  0L,                    /* No special class style */
  2166.                  NULLHANDLE,                    /* Resource is in .EXE file */
  2167.                  ID_PMICS,                      /* Frame window identifier */
  2168.                  &hClient               /* Client window handle returned */
  2169.                  );
  2170.  
  2171.     WinSetWindowPos(hFrame, 0L,
  2172.                     (SHORT)20, (SHORT)20, /* offset of lower left */
  2173.                     (SHORT)500, (SHORT)500,    /* dimension */
  2174.                     SWP_SIZE | SWP_MOVE);
  2175.     WinSetFocus(HWND_DESKTOP, hFrame);
  2176.  
  2177.     WinCreateWindow(WinQueryObjectWindow(hClient),
  2178.                     WC_LISTBOX, "new button", WS_VISIBLE,
  2179.                     0,0, 200,100, HWND_TOP, hFrame, 5000, NULL, NULL);
  2180.     WinCreateWindow(HWND_DESKTOP, WC_LISTBOX, "new button2", WS_VISIBLE,
  2181.                     0,0,200,100,NULLHANDLE, HWND_TOP, 600, NULL, NULL);
  2182. /*      WinFillRect (hps, &rcInvalid, color);
  2183.         for (rank = 0; rank <= 8; rank++)
  2184.           DrawLine(hps, LBX, LBY+rank*SQUARESIZE,
  2185.                    LBX+8*SQUARESIZE, LBY+rank*SQUARESIZE);
  2186.         for (file = 0; file <= 8; file++)
  2187.           DrawLine(hps, LBX+file*SQUARESIZE, LBY,
  2188.                    LBX+file*SQUARESIZE, LBY+8*SQUARESIZE);*/
  2189.  
  2190. /* from window scrolling in TermPut
  2191.           HRGN hrgn;
  2192.           RECTL lineRect;
  2193.  
  2194.           currow = (++currow) % maxrow;
  2195.           p.x = 10;
  2196.           p.y = (16*(maxrow-currow));
  2197.           GpiMove(hps, &p);
  2198.           lineRect.xLeft = p.x;
  2199.           lineRect.yBottom = p.y;
  2200.           lineRect.xRight = FW_X;
  2201.           lineRect.yTop = p.y + 15;
  2202.           GpiSetBackColor(hps, CLR_DARKGRAY);
  2203.           GpiSetColor(hps, CLR_PINK);
  2204.           hrgn = GpiCreateRegion(hps, 1, &lineRect);
  2205.           GpiPaintRegion(hps, hrgn);*/
  2206. #define LAST(n) (charSilo[(siloPos-(n)) & 0xff])
  2207.         int             i,j,k;
  2208.         charSilo[siloPos++] = CHAR1FROMMP(mp1);
  2209.         if (LAST(1) == '@' && LAST(2) == '#' && LAST(3) == '@')
  2210.           {   /* wow, a status message has arrived */
  2211.             for (i=4; i<256; i++)
  2212.               if (LAST(i) == '#' && LAST(i-1) == '@' && LAST(i-2) == '#')
  2213.                 break;
  2214.             if (i == 256) return (MRESULT)FALSE;  /* error */
  2215.             for (k=0,j=i; j>=1; j--,k++)
  2216.               s[k] = LAST(j);
  2217.             s[k] = '\0';
  2218.             s2 = ProcessStatusMsg(s);
  2219.             WinInvalidateRegion(boardMethod, NULLHANDLE, 0);
  2220.           }
  2221. #endif
  2222.